2013-12-17 67 views
2

我对线程相对较新,而且我仍在学习最佳技术和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; 

我不能完全肯定这个,所以我开始研究,我发现,挥发性实际上并不需要同步,而且实际上通常是有害的。此外,我发现this answer,其中描述了一个几乎与我有关的过程相同的过程。然而,在答案的评论中,这种解决方案被描述为中断,因为易失性不能保证不同的处理器内核容易(如果有的话)在易失性值上传达更改。

我的问题是这样的:我应该使用原子标志,还是其他什么东西?究竟什么是缺乏易变性的财产,然后由需要什么构造来有效解决我的问题?

+0

你的程序有一个数据竞争,所以确实是非常糟糕的。使用'std :: atomic '或类似的东西。 (也许是'std :: atomic_flag'。) –

+0

@KerrekSB你能否解释为什么它有数据竞争?工作线程只读取共享变量,并且在线程运行时不访问任何数据。 – Svalorzen

+1

因为语言是这样说的。你有多个访问,其中至少有一个是写入,而没有任何排序,并且内存位置不是'std :: atomic'。 –

回答

2

您是否在寻找互斥锁?它们是为了锁定线程而避免共享数据上的冲突。这是你在找什么?

+0

因为我只会在工作线程没有运行时访问共享数据,所以我不认为我实际上需要一个互斥量。对我而言,问题只是设法停止线程,然后我可以执行任何需要的同步。 – Svalorzen

+0

您无法知道操作系统何时计划或停止线程,因此逻辑会变得困难,因为您需要引入某些事件处理程序,并在所有线程最终停止运行时运行 – lolski

+0

您希望它停止它绝对? 如果是这样:http://msdn.microsoft.com/en-us/library/windows/desktop/ms682659%28v=vs.85%29.aspx 那么,这是Win Threads的一个函数。 – tho

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(); 
} 
+0

谢谢你的链接。我不确定我需要一个互斥体,因为我只会在关闭线程时访问线程正在处理的数据,并且在每次迭代结束时,线程离开的数据处于完美状态。流会像这样:启动线程 - >停止线程 - >读取数据 - >启动线程 - >停止线程 - >读取数据等等。 – Svalorzen

0

我会建议使用std::mutexstd::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 S也是一样的。旋转锁可能比互斥锁慢。所以我再重复升压网站上的提醒:

Do not use spinlocks unless you are certain that you understand the consequences.

我相信,互斥和条件变量是你的情况的路要走。