C ++ 11非阻塞,长期运行的生产者消费者线程

时间:2016-10-09 21:41:40

标签: multithreading c++11

我正在尝试自学C ++ 11线程,我想在应用程序开始时启动后台生成器线程,并让它运行直到应用程序退出。我还想拥有消费者线程(也可以在应用程序的生命周期内运行)。

一个真实的例子是生产者线程在Com端口上侦听传入的GPS数据。一旦累积了完整的消息,就可以解析它是否是一个感兴趣的消息,然后转换成一个字符串(比如说),并且'交付回来'被消费(例如,更新当前位置)。

我的问题是,当我加入()时,我无法在不阻止其他应用程序的情况下弄清楚如何执行此操作。在消费者线程上。

这是我非常简化的示例,希望能够展示我的问题:

#include <QCoreApplication>
#include <QDebug>
#include <thread>
#include <atomic>
#include <iostream>
#include <queue>
#include <mutex>
#include <chrono>
#include "threadsafequeuetwo.h"

ThreadSafeQueueTwo<int> goods;
std::mutex mainMutex;

std::atomic<bool> isApplicationRunning = false;

void theProducer ()
{
    std::atomic<int> itr = 0;
    while(isApplicationRunning)
    {
        // Simulate this taking some time...
        std::this_thread::sleep_for(std::chrono::milliseconds(60));

        // Push the "produced" value onto the queue...
        goods.push(++itr);

        // Diagnostic printout only...
        if ((itr % 10) == 0)
        {
            std::unique_lock<std::mutex> lock(mainMutex);
            std::cout << "PUSH " << itr << " on thread ID: "
                  << std::this_thread::get_id() << std::endl;
        }

        // Thread ending logic.
        if (itr > 100) isApplicationRunning = false;
    }
}

void theConsumer ()
{
    while(isApplicationRunning || !goods.empty())
    {
        int val;

        // Wait on new values, and 'pop' when available...
        goods.waitAndPop(val);

        // Here, we would 'do something' with the new values...
        // Simulate this taking some time...
        std::this_thread::sleep_for(std::chrono::milliseconds(10));

        // Diagnostic printout only...
        if ((val % 10) == 0)
        {
            std::unique_lock<std::mutex> lock(mainMutex);
            std::cout << "POP " << val << " on thread ID: "
                  << std::this_thread::get_id() << std::endl;
        }
    }
}

int main(int argc, char *argv[])
{
    std::cout << "MAIN running on thread ID: "
              << std::this_thread::get_id() << std::endl;

    // This varaiable gets set to true at startup, and,
    // would only get set to false when the application
    // wants to exit.
    isApplicationRunning = true;

    std::thread producerThread (theProducer);
    std::thread consumerThread (theConsumer);

    producerThread.detach();
    consumerThread.join();      // BLOCKS!!! - how to get around this???

    std::cout << "MAIN ending on thread ID: "
              << std::this_thread::get_id() << std::endl;
}

ThreadSafeQueueTwo类是线程安全的队列实现,几乎完全取自&#34; C ++ Concurrency In Action&#34;书。这似乎工作得很好。如果有人对此感兴趣:

#ifndef THREADSAFEQUEUETWO_H
#define THREADSAFEQUEUETWO_H

#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>

template<typename T>
class ThreadSafeQueueTwo
{
public:
    ThreadSafeQueueTwo()
    {}

    ThreadSafeQueueTwo(ThreadSafeQueueTwo const& rhs)
    {
        std::lock_guard<std::mutex> lock(myMutex);
        myQueue = rhs.myQueue;
    }

    void push(T newValue)
    {
        std::lock_guard<std::mutex> lock(myMutex);
        myQueue.push(newValue);
        myCondVar.notify_one();
    }

    void waitAndPop(T& value)
    {
        std::unique_lock<std::mutex> lock(myMutex);
        myCondVar.wait(lock, [this]{return !myQueue.empty(); });
        value = myQueue.front();
        myQueue.pop();
    }

    std::shared_ptr<T> waitAndPop()
    {
        std::unique_lock<std::mutex> lock(myMutex);
        myCondVar.wait(lock, [this]{return !myQueue.empty(); });
        std::shared_ptr<T> sharedPtrToT (std::make_shared<T>(myQueue.front()));
        myQueue.pop();
        return sharedPtrToT;
    }

    bool tryPop(T& value)
    {
        std::lock_guard<std::mutex> lock(myMutex);
        if (myQueue.empty())
            return false;
        value = myQueue.front();
        myQueue.pop();
        return true;
    }

    std::shared_ptr<T> tryPop()
    {
        std::lock_guard<std::mutex> lock(myMutex);
        if (myQueue.empty())
            return std::shared_ptr<T>();
        std::shared_ptr<T> sharedPtrToT (std::make_shared<T>(myQueue.front()));
        myQueue.pop();
        return sharedPtrToT;
    }

    bool empty()
    {
        std::lock_guard<std::mutex> lock(myMutex);
        return myQueue.empty();
    }

private:
    mutable std::mutex      myMutex;
    std::queue<T>           myQueue;
    std::condition_variable myCondVar;
};

#endif // THREADSAFEQUEUETWO_H

Here's the output:

我知道我的例子有明显的问题,但我的主要问题是如何在后台运行这样的东西而不阻塞主线程?

或许更好的方法是尝试解决这个问题,有没有一种方法,每次制作人生产&#39;一些新数据,我可以简单地在主线程中调用一个方法,传入新数据吗?这类似于Qt的排队信号/插槽,我很喜欢。

0 个答案:

没有答案