Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 通知线程退出_C++_Multithreading_C++11_Threadpool - Fatal编程技术网

C++ 通知线程退出

C++ 通知线程退出,c++,multithreading,c++11,threadpool,C++,Multithreading,C++11,Threadpool,下面是线程池的一个简单(可能是幼稚的)实现 我想知道,根据下面的方法,是否有一种很好的方法可以主动通知线程池线程退出,而不必在每次超时后检查布尔值mStopped 我知道有更好的方法来实现线程池——但我仍然有兴趣看看下面的代码是否可以在不从根本上改变它的情况下得到改进 我很高兴听到一般性的建议。。。不一定要修复下面的代码。。。问题实际上是关于发送信号/等待线程,线程池只是提供一些上下文 我使用的是GCC4.4.6(因此下面的一些语法有点过时),代码是用g++--std=c++0x main.cc

下面是线程池的一个简单(可能是幼稚的)实现

我想知道,根据下面的方法,是否有一种很好的方法可以主动通知线程池线程退出,而不必在每次超时后检查布尔值
mStopped

我知道有更好的方法来实现线程池——但我仍然有兴趣看看下面的代码是否可以在不从根本上改变它的情况下得到改进

我很高兴听到一般性的建议。。。不一定要修复下面的代码。。。问题实际上是关于发送信号/等待线程,线程池只是提供一些上下文

我使用的是GCC4.4.6(因此下面的一些语法有点过时),代码是用
g++--std=c++0x main.cc-pthread编译的

#include <vector>
#include <mutex>
#include <thread>
#include <deque>
#include <condition_variable>
#include <functional>

using namespace std;

struct ThreadPool;

struct Worker {
  ThreadPool& mThreadPool;
  Worker(ThreadPool& threadPool) : mThreadPool(threadPool) {}
  void operator()();
};

struct ThreadPool {
  vector<thread> mWorkers;
  deque<function<void()>> mTasks;
  bool mStopped; // not atomic
  mutex mMutex;
  condition_variable mCond;

  ThreadPool() : mStopped(false) {
    for (size_t i = 0; i < 5; i++)
      mWorkers.push_back(thread(Worker(*this)));
  }

  ~ThreadPool() { stop();  }

  void stop() {
    if (!mStopped) {
      mStopped = true;
      for (auto it = mWorkers.begin(); it != mWorkers.end(); ++it)
        if (it->joinable()) it->join();
    }
  }

  bool canBreakFromWait() const { return !mTasks.empty(); }

  void enqueue(function<void()> f) {
    if (mStopped) return;
    unique_lock<mutex> lck(mMutex);
    mTasks.push_back(f);
    mCond.notify_one();
  }
};

void Worker::operator()() {
  while (true) {
    unique_lock<mutex> lck(mThreadPool.mMutex);
    mThreadPool.mCond.wait_for(lck, chrono::seconds(1), bind(&ThreadPool::canBreakFromWait, &mThreadPool));
    if (mThreadPool.mStopped) break;
    auto task = mThreadPool.mTasks.front();
    mThreadPool.mTasks.pop_front();
    lck.unlock();
    task();
  }
}

void doWork(int data) {}

int main() {
  ThreadPool threadPool;
  for (auto i = 0; i < 50; i++)
    threadPool.enqueue(bind(doWork, i));
  threadPool.stop();
}
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
结构线程池;
结构工人{
线程池&mThreadPool;
辅助线程(线程池和线程池):mThreadPool(线程池){}
void运算符();
};
结构线程池{
媒介工作者;
德克姆塔克斯;
bool mStopped;//不是原子的
互斥体mMutex;
条件变量mCond;
线程池():mStopped(false){
对于(大小i=0;i<5;i++)
向后推(线程(工作者(*this));
}
~ThreadPool(){stop();}
无效停止(){
如果(!mStopped){
mStopped=true;
对于(自动it=mWorkers.begin();it!=mWorkers.end();++it)
如果(it->joinable())it->join();
}
}
bool canBreakFromWait()常量{return!mTasks.empty();}
无效排队(函数f){
如果(MST)返回;
唯一锁定lck(mMutex);
mTasks.推回(f);
通知某人;
}
};
void Worker::operator()(){
while(true){
唯一的锁lck(mThreadPool.mMutex);
mThreadPool.mCond.wait_for(lck,chrono::seconds(1),bind(&ThreadPool::canBreakFromWait,&mThreadPool));
如果(mThreadPool.mStopped)中断;
auto task=mThreadPool.mTasks.front();
mThreadPool.mTasks.pop_front();
lck.unlock();
任务();
}
}
void doWork(int数据){}
int main(){
线程池线程池;
用于(自动i=0;i<50;i++)
排队(bind(doWork,i));
threadPool.stop();
}
两条评论

第一个是因为
mStopped
是在一个线程中修改的, 并且在其他线程中访问时,对它的所有访问都必须是 同步的。目前,您的程序尚未定义 行为。我不知道这在实践中是否会成为一个问题 知道;先验地,编译器可以在
stop
中推断出 线程访问变量,并且在 函数返回后,线程调用
stop
,依此类推 取消指定

第二,如果我有工作清单,我会 一般认为创建一个特殊的工作是最简单的 终止线程。标准螺纹似乎没有 一个
thread\u exit
函数,但可以通过 让作业返回布尔值或使用异常。 然后,
stop
函数锁定互斥锁,清空队列,然后 将这些特殊终止作业之一插入队列
对于每个线程。

必须同步对
mStopped
的所有访问。谢谢。我同意它们应该是一般性的,但我不认为这会影响所给出的示例(即,在这种情况下,误读MSTOPED并不是灾难性的)。如果我错了,请纠正我。标准上说的是未定义的行为。从理论上讲,在低得多的级别上,您可能永远不会在其中一个线程中看到它
true
。(实际上…)锁定队列、排空队列,然后放入终止作业似乎是一种很好的方法。