通知线程退出

Notifying threads to exit

本文关键字:退出 线程 通知      更新时间:2023-10-16

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

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

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

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

我使用的是 gcc 4.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();
}

两条评论。

首先,由于mStopped在一个线程中被修改,并在其他线程中访问,对它的所有访问都必须同步。 就目前而言,您的程序尚未定义行为。 这在实践中是否会成为问题,我不知道;先验地,编译器可以stop推断出没有其他人线程访问变量,并且未在函数返回后调用stop线程,依此类推禁止分配。

第二个是,如果我有工作列表,我已经通常发现创建一个特殊的工作是最简单的终止线程。 标准线程似乎没有一个thread_exit函数,但这可以很容易地通过让作业返回布尔值或使用异常。然后,stop函数锁定互斥锁,清空队列,然后将这些特殊终止作业之一插入队列对于每个线程。