问题描述
我正在编写一个共享字符串“队列”的程序:
- 2 或 3 个线程推回队列
- UI 线程每 0.5 - 1 秒从队列中弹出字符串。 (UI 线程表示 CWnd::OnTimer)
其中一个写入线程非常频繁地将字符串推回。 (字符串实际上是一个日志,每秒生成 5 - 10 行。)
关于上面的解释,我附加了以下代码片段。
class Logger {
std::mutex m_mutex;
std::list<std::string> m_queLogs;
public:
int info(std::string zLog) {
std::lock_guard<std::mutex> lk(m_mutex);
m_queLogs.push_back(std::move(zLog));
...
}
std::string popLog() { //!!!!! Do I need to add a lock_guard here?
if (m_queLogs.size() == 0)
return "";
auto zLog = m_queLogs.front();
m_queLogs.pop_front();
return zLog;
}
}
// Thread 1
int TcpComm::OnRecv(int opCode,char* buf) {
switch (opCode) {
case CODE_LOG: // generated nearly Real-time
Logger::instance()->info(buf);
break;
...
}
...
}
// Thread 2
void MonitorThread(LPVOID lpvoid) {
while (1) {
Sleep(60 * 1000); // generated some times.
Logger::instance()->info(" ---- monitor signal --- ");
...
}
}
// UI Thread
void CLogView::OnTimer(UINT_PTR nIDEvent)
{
// every 500 milisecond.
auto zLog = Logger::instance()->popLog();
CString strLog = convert_utf8_to_cstring(zLog);
m_ctrLogView.AppendString(strLog);
}
m_queLogs
的字符串永远不会被删除,只会在写入线程中被推回。
只有 UI 线程从 m_queLogs
中弹出日志。
我认为不锁定 Logger::popLog()
没有问题,但不确定如果日志记录频率增加。
请帮助我做出决定。
解决方法
是的。读取器必须锁定以避免写入与读取相关的无序写入,这会导致未定义的行为。
研究非阻塞队列数据结构可能会有好处。我认为多个作者必须锁定,但读者可以免费等待。但请记住,免费等待并不一定意味着高效。