【问题标题】:How to safely and properly use threads in C++?如何在 C++ 中安全正确地使用线程?
【发布时间】:2021-08-16 09:08:41
【问题描述】:

我的应用程序有一个日志系统现在这就是我要做的:

static void Background() {
    while(IsAlive){
         while(!logs.empty()){
             ShowLog(log.front()); 
             log.pop();
         }
         while(logs.empty()){
             Sleep(200);
         }
    }
}

static void Init(){
    // Some Checks
    Logger::backgroundThread = std::thread(Background);
    backgroundThread.detach();
}

static void Log(std::string log){ 
    logs.push(log);
}

static void ShowLog(std::string log){
    // Actual implementation is bit complex but that does not involve threads so i guess it is irrelevant for this question
    std::cout << log << std::endl;
}

这里是logstd::queue&lt;std::string&gt;

现在我不太确定这是否是一个好方法。

有没有更好的方法来实现这一点。

注意我使用的是 C++17

【问题讨论】:

  • 至少您需要查看std::mutex 或无锁队列,以同时保护程序免受pushing 和popping 的影响。
  • while(logs.empty()){ Sleep(200); } - 使用 std::condition_variable 而不是这样的结构。
  • 关注几分钟前问的this question。它非常相似,它得到的任何答案都将适用于您的案例。
  • 为您提供很棒的日志库列表here,如果只是为了灵感。
  • 不是线程安全,而是在void Log中使用std::move(log)

标签: c++ multithreading parallel-processing thread-safety c++17


【解决方案1】:
namespace {  // Anonymous namespace instead of static functions.

std::mutex log_mutex;

void Background() {
    while(IsAlive){
        std::queue<std::string> log_records;
        {
            // Exchange data for minimizing lock time.
            std::unique_lock lock(log_mutex);
            logs.swap(log_records);
        }
        if (log_records.empty()) {
            Sleep(200);
            continue;
        }
        while(!log_records.empty()){
            ShowLog(log_records.front()); 
            log_records.pop();
        }
    }
}

void Log(std::string log){
    std::unique_lock lock(log_mutex);
    logs.push(std::move(log));
}

}

【讨论】:

  • 我只想说一件事,我把睡眠放在那里只是为了减少 CPU 使用率,所以如果有更好的方法你可能不会使用它
  • @JaysmitoMukherjee 替换睡眠的简单方法是使用std::condition_variable。生产者 (Log) 和消费者 (Background) 共享一个 condition_variable 实例。消费者在condition_variable 上等待,在生产者将一个项目放入队列后,它用condition_variable 通知消费者。链接文档页面底部的好示例。
  • @user4581301 我确实更改了我的代码以使用条件变量,但我不知道为什么如果我使用条件变量,CPU 使用率会上升到 10% 到 12%,而在这种方法中它会最大化在相同条件下减少 5% 到 6% 的广告
  • @JaysmitoMukherjee 可能值得用您的新代码提出一个新问题。条件变量方法应该导致记录器仅在需要时唤醒。您可能记录得太快以至于每次都唤醒是错误的选择,但工具箱中可能有一个更具教育意义的答案。
  • @user4581301 实际上这不是我拥有的实际代码,而是高度简化的代码,以便专注于我认为更重要的事情(线程安全)。但你是对的。这是我的游戏引擎的日志系统,因此可能需要非常快速的日志记录。我的主要优先事项是让这个程序尽可能高效(快速),这样它就不会成为引擎的积压工作。为了快速记录,我做到了。我使用鼠标移动事件进行了测试(因为这应该是大量的日志记录和最大合理的日志记录量)以及所有鼠标记录和发送日志
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-27
  • 1970-01-01
相关资源
最近更新 更多