使用std :: async()& std :: move()以异步方式将数据传递给另一个线程

时间:2014-12-01 06:44:23

标签: c++ multithreading c++11 asynchronous boost

我真的想看看这两个线程函数RunThread1() & RunThread1()如何并行运行。每次运行RunThread1()时都会阻止RunThread2(),反之亦然。

我不想等到future完成,因此我将std::asyncstd::move一起使用 我正在使用scoped_lock,但我不认为这是一个问题。

我正在设计一个异步响应处理引擎,一个线程插入数据,而另一个线程从另一端读取它。

可能出现此问题的任何建议?有关整体设计的任何建议。

#include <windows.h>

#include <string>
#include <iostream>
#include <vector>
#include <deque>
#include <chrono>
#include <thread>
#include <future>

#include <boost/scoped_ptr.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>

using namespace std;
using namespace boost;

template<typename R>
bool Is_future_ready(std::future<R> const& f)
{
    return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}

std::vector<std::future<void>> pending_futures;

class A
{
private:
    boost::thread*                myFunc1Thread;
    boost::thread*                myFunc2Thread;

public:
    A()
    {
        myFunc1Thread = nullptr;
        myFunc2Thread = nullptr;
    }

    void RunThreads();
    void RunThread1();
    void RunThread2();

    void PopulateResponses(vector<string> responses);
    void PopulateResponse(string response);

    struct Record
    {
        char response[128];

        Record(const char* response)
        {
            memset(this->response,0,sizeof(this->response));
            strcpy(this->response, response);
        }

        ~Record()
        {
        }

        Record& operator= (const Record& cmd)
        {
            if(this == &cmd)       // Same object?
            {
                return *this;
            }

            memset(this->response,0,sizeof(this->response));
            strcpy(this->response, cmd.response);
            return *this;
        }
    };

    typedef deque<Record> RecordsQueue;
};

boost::mutex ResponseMutex;

A::RecordsQueue Records;

void A::RunThreads()
{
    myFunc1Thread = new boost::thread(boost::bind(&A::RunThread1, this));
    HANDLE threadHandle1 = myFunc1Thread->native_handle();
    SetThreadPriority(threadHandle1, THREAD_PRIORITY_NORMAL);

    myFunc2Thread = new boost::thread(boost::bind(&A::RunThread2, this));
    HANDLE threadHandle2 = myFunc2Thread->native_handle();
    SetThreadPriority(threadHandle2, THREAD_PRIORITY_NORMAL);

    myFunc1Thread->join();
    myFunc2Thread->join();
}

void A::PopulateResponse(string response)
{
    Records.push_back(Record(response.c_str()));
}

void A::PopulateResponses(vector<string> responses)
{
    boost::mutex::scoped_lock lock(ResponseMutex);
    std::for_each(responses.begin(), responses.end(), bind1st(mem_fun(&A::PopulateResponse), this));
}

void A::RunThread1()
{
    int i = 0;

    while(true)
    {
        vector<string> responses;
        responses.push_back(to_string(i));
        cout<< "Added: " << to_string(i) << endl;
        i++;

        pending_futures.erase(std::remove_if( pending_futures.begin(), pending_futures.end(), Is_future_ready<void>), pending_futures.end());
        auto f = std::async (std::launch::async, &A::PopulateResponses, this, responses);
        pending_futures.push_back(std::move(f));
    }
}

void A::RunThread2()
{
    while(true)
    {
        boost::mutex::scoped_lock lock(ResponseMutex);
        if(!Records.empty())
        {              
            Record res = Records.front();
            cout<< "Processed: " << res.response << endl;

            //some lengthy processing...., let's use sleep() to depict that
            boost::this_thread::sleep(boost::posix_time::seconds(1));

            Records.pop_front();
        }
    }
}

int main()
{
    A a;
    a.RunThreads();
}

1 个答案:

答案 0 :(得分:2)

您正在紧缩地添加期货:

void RunThread1() {
    while(true)
    {
        // ... 
        auto f = std::async (std::launch::async, &A::PopulateResponses, this, responses);
        pending_futures.push_back(std::move(f));
    }
}

难怪没有什么能跟上它。其他线程正在进行所有锁定(线程1没有阻塞操作,但Is_future_ready可能会强制线程产生,我不确定)。

在循环中的某处添加一个睡眠,你会发现事情正在按预期工作。

boost::this_thread::sleep_for(boost::chrono::seconds(1));

请记住,这仍然很脆弱:这取决于时机是否正确。为了更加通用,请使用正确的消息/任务队列,并在队列满时阻止推送端。