正确关闭提升螺纹

时间:2015-06-11 09:12:06

标签: c++ multithreading boost

我有x个提升线程同时工作。一个生产者线程使用计算任务填充同步队列。消费者线程弹出任务并计算它们。

Synchronised Queue 图片来源:https://www.quantnet.com/threads/c-multithreading-in-boost.10028/

用户可以在此过程中完成程序,因此我需要正确关闭我的线程。我当前的方法似乎不起作用,因为抛出异常。它的目的是在系统关闭时,所有进程都应该被杀死并且无论他们做什么都会停止当前的任务。你能告诉我,你怎么会杀死那些线程?

线程初始化:

    for (int i = 0; i < numberOfThreads; i++)
    {
        std::thread* thread = new std::thread(&MyManager::worker, this);
        mThreads.push_back(thread);
    }

线程销毁:

void MyManager::shutdown()
{
    for (int i = 0; i < numberOfThreads; i++)
    {
        mThreads.at(i)->join();
        delete mThreads.at(i);
    }
    mThreads.clear();
}

工人:

void MyManager::worker()
{
    while (true)
    {

        int current = waitingList.pop();
        Object * p = objects.at(current);
        p->calculateMesh(); //this task is internally locked by a mutex

        try
        {
            boost::this_thread::interruption_point();
        }
        catch (const boost::thread_interrupted&)
        {
            // Thread interruption request received, break the loop
            std::cout << "- Thread interrupted. Exiting thread." << std::endl;
            break;
        }
    }
}

同步队列:

#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>

template <typename T>
class ThreadSafeQueue
{
public:

    T pop()
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        while (queue_.empty())
        {
            cond_.wait(mlock);
        }
        auto item = queue_.front();
        queue_.pop();

        return item;
    }

    void push(const T& item)
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        queue_.push(item);
        mlock.unlock();
        cond_.notify_one();
    }


    int sizeIndicator()
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        return queue_.size();
    }


private:

    bool isEmpty() {
        std::unique_lock<std::mutex> mlock(mutex_);
        return queue_.empty();
    }

    std::queue<T> queue_;
    std::mutex mutex_;
    std::condition_variable cond_;
};

抛出的错误调用堆栈:

... std::_Mtx_lockX(_Mtx_internal_imp_t * * _Mtx) Line 68   C++
... std::_Mutex_base::lock() Line 42    C++
... std::unique_lock<std::mutex>::unique_lock<std::mutex>(std::mutex & _Mtx) Line 220   C++
... ThreadSafeQueue<int>::pop() Line 13 C++
... MyManager::worker() Zeile 178   C++

4 个答案:

答案 0 :(得分:3)

根据我在Boost和Java中使用线程的经验,尝试从外部关闭线程总是很麻烦。我从来没有真正能够干净利落地工作。

我得到的最好的方法是为所有设置为true的消费者线程提供一个布尔值。当您将其设置为false时,线程将自行返回。在您的情况下,可以很容易地将其放入您的while循环中。

最重要的是,您需要进行一些同步,以便在删除之前等待线程返回,否则您可能会难以定义行为。

我过去的一个项目的例子:

线程创建

barrier = new boost::barrier(numOfThreads + 1);
threads = new detail::updater_thread*[numOfThreads];

for (unsigned int t = 0; t < numOfThreads; t++) {
    //This object is just a wrapper class for the boost thread.
    threads[t] = new detail::updater_thread(barrier, this);
}

线程破坏

for (unsigned int i = 0; i < numOfThreads; i++) {
    threads[i]->requestStop();//Notify all threads to stop.
}

barrier->wait();//The update request will allow the threads to get the message to shutdown.

for (unsigned int i = 0; i < numOfThreads; i++) {
    threads[i]->waitForStop();//Wait for all threads to stop.
    delete threads[i];//Now we are safe to clean up.
}

线程包装器可能感兴趣的一些方法。

//Constructor
updater_thread::updater_thread(boost::barrier * barrier)
{
   this->barrier = barrier;
   running = true;

   thread = boost::thread(&updater_thread::run, this);
}

void updater_thread::run() {
    while (running) {
        barrier->wait();
        if (!running) break;

        //Do stuff

        barrier->wait();
    }
}

void updater_thread::requestStop() {
    running = false;
}

void updater_thread::waitForStop() {
    thread.join();
}

答案 1 :(得分:0)

尝试移动&#39;尝试&#39; up(如下面的示例)。如果您的线程正在等待数据(在waitingList.pop()内),则可能在条件变量.wait()内等待。这是一个“中断点”。因此,当线程被中断时可能会抛出。

void MyManager::worker()
{
    while (true)
    {
        try
        {
            int current = waitingList.pop();
            Object * p = objects.at(current);
            p->calculateMesh(); //this task is internally locked by a mutex

            boost::this_thread::interruption_point();
        }
        catch (const boost::thread_interrupted&)
        {
            // Thread interruption request received, break the loop
            std::cout << "- Thread interrupted. Exiting thread." << std::endl;
            break;
        }
    }
}

答案 2 :(得分:0)

也许你正在捕捉错误的异常类? 这意味着它不会被抓住。 不太熟悉线程,但它是std :: threads和boost :: threads的混合导致了这个吗?

尝试捕获最低的父异常。

答案 3 :(得分:-2)

我认为这是读写器线程在公共缓冲区上工作的经典问题。解决此问题的最安全方法之一是使用互斥和信号。(我无法在此处发布代码。请发送电子邮件给我,我将代码发布给您)。