我对线程比较新,我还在学习最好的技术和C ++ 11线程库。现在我正在实现一个无限循环,执行一些工作的工作线程。理想情况下,主线程会不时地停止循环以与工作线程正在生成的信息同步,然后再次启动它。我的想法最初是这样的:
// Code run by worker thread
void thread() {
while(run_) {
// Do lots of work
}
}
// Code run by main thread
void start() {
if ( run_ ) return;
run_ = true;
// Start thread
}
void stop() {
if ( !run_ ) return;
run_ = false;
// Join thread
}
// Somewhere else
volatile bool run_ = false;
我对此并不完全确定,所以我开始研究,我发现实际上不需要volatile来实现同步,实际上通常是有害的。另外,我发现了this answer,它描述了一个与我的过程几乎相同的过程。然而,在答案的评论中,这个解决方案被描述为已经破解,因为volatile不能保证不同的处理器核心(如果有的话)能够在易失性值上进行通信的变化。
我的问题是:我应该使用原子旗帜还是完全不同的东西?究竟什么是缺乏volatile的属性,然后由有效解决我的问题所需的任何构造提供?
答案 0 :(得分:2)
你找过Mutex吗?它们可以锁定线程,避免共享数据冲突。这是你在找什么?
答案 1 :(得分:1)
我认为你想使用barrier synchronization使用std::mutex?
另请查看boost thread,了解相对较高级别的线程库
从链接中查看此代码示例:
#include <iostream>
#include <map>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>
std::map<std::string, std::string> g_pages;
std::mutex g_pages_mutex;
void save_page(const std::string &url)
{
// simulate a long page fetch
std::this_thread::sleep_for(std::chrono::seconds(2));
std::string result = "fake content";
g_pages_mutex.lock();
g_pages[url] = result;
g_pages_mutex.unlock();
}
int main()
{
std::thread t1(save_page, "http://foo");
std::thread t2(save_page, "http://bar");
t1.join();
t2.join();
g_pages_mutex.lock(); // not necessary as the threads are joined, but good style
for (const auto &pair : g_pages) {
std::cout << pair.first << " => " << pair.second << '\n';
}
g_pages_mutex.unlock();
}
答案 2 :(得分:0)
我建议使用std::mutex
和std::condition_variable
来解决问题。下面是一个如何使用C ++ 11的示例:
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
int main()
{
mutex m;
condition_variable cv;
// Tells, if the worker should stop its work
bool done = false;
// Zero means, it can be filled by the worker thread.
// Non-zero means, it can be consumed by the main thread.
int result = 0;
// run worker thread
auto t = thread{ [&]{
auto bound = 1000;
for (;;) // ever
{
auto sum = 0;
for ( auto i = 0; i != bound; ++i )
sum += i;
++bound;
auto lock = unique_lock<mutex>( m );
// wait until we can safely write the result
cv.wait( lock, [&]{ return result == 0; });
// write the result
result = sum;
// wake up the consuming thread
cv.notify_one();
// exit the loop, if flag is set. This must be
// done with mutex protection. Hence this is not
// in the for-condition expression.
if ( done )
break;
}
} };
// the main threads loop
for ( auto i = 0; i != 20; ++i )
{
auto r = 0;
{
// lock the mutex
auto lock = unique_lock<mutex>( m );
// wait until we can safely read the result
cv.wait( lock, [&]{ return result != 0; } );
// read the result
r = result;
// set result to zero so the worker can
// continue to produce new results.
result = 0;
// wake up the producer
cv.notify_one();
// the lock is released here (the end of the scope)
}
// do time consuming io at the side.
cout << r << endl;
}
// tell the worker to stop
{
auto lock = unique_lock<mutex>( m );
result = 0;
done = true;
// again the lock is released here
}
// wait for the worker to finish.
t.join();
cout << "Finished." << endl;
}
你可以通过实质上实现自旋锁来对std::atomic
做同样的事情。旋转锁可以比互斥锁慢。所以我在boost网站上重复建议:
Do not use spinlocks unless you are certain that you understand the consequences.
我相信互斥体和条件变量是您的理由。