并发编程9——async、future,promise,packaged_task

目录

一、std::async和std::future

1.1 函数示例

async是一个函数模板,可以启动一个异步任务,启动这个异步任务后可以返回一个std::future对象。

  • 启动一个异步任务是指——自动创建一个线程并开始执行对应的线程入口函数,返回一个future对象。

这个future对象里面含有线程入口函数所返回的结果,这个结果会在线程执行完毕的时候拿到。

本质上,是把std::future对象和线程mythread绑定在一起了。所以执行到result.get()的时候,一定要等到mythread执行完,才可以继续执行下去,如果mythread没有执行完,会停在那里等待。

结果

可以看到,先执行了主线程,但是先继续执行continue(即使先调用了async(mythread)),然后是子线程打印,需要get()获取子线程的结果,所以停下来等待,然后线程将结果返回给future对象result

  • 本质上就是通过future对象的get()成员函数来等待线程结束并返回结果,如果get()拿不到结果,就会卡在那里等着。还有个wait()函数,也是等待线程返回,但是不能返回结果get()只能调用一次。

1.2 std::lunch

有一个函数std::launch::deferred可以延迟线程入口函数调用到get()调用的时候才执行。
因为上面我们发现,就算不调用get(),主线程执行完了,也会在return 0那里等待子线程执行完。如果我们加了launch延迟,会导致子线程根本不会执行,因为没有调用成员函数get()

子线程没有执行
  • 本质上,有launch::deferred后,线程都没有创建出来。

但是!如果调用了get()(在基于std::launch::deferred的情况下),会发现主线程ID和子线程ID是一样的!

主线程ID和子线程ID是一样的
  • 本质上说明deferred这个延迟调用并没有创建子线程,是在主线程中调用的线程入口函数

1.3 std::launch::async

std::launch::async这个标记,可以让在调用async函数的时候就立即开始创建线程,而不需要等待执行到get()的时候再调用,而且会创建一个新的线程。

二、std::packaged_task

这是一个类模板,模板参数是各种可调用对象,通过packaged task可以把各种可调用对象包装起来,然后作为线程入口函数使用。

三、std::promise

std::promise是一个类模板

可以在某个线程中给它赋值,然后可以在其他线程中,把这个值取出来用。

通过promise和future实现2个线程的消息传递

2个线程之间消息的传递

小结


博客示例源代码

  • 单独的函数作为线程入口
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

int mythread()
{
    cout << "mythread() start" << "thread_id = " << std::this_thread::get_id() << endl;
    
    std::chrono::milliseconds dura(5000);
    std::this_thread::sleep_for(dura);

    cout << "mythread() end" << "thread_id = " << std::this_thread::get_id() << endl;

    return 5;
}

int main()
{
    cout << "main" << "thread_id = " << std::this_thread::get_id() << endl;
    std::future result = std::async(mythread);
    cout << "continue...!" << endl;

    int def; 
    def = 0;

    cout << result.get() << endl;
    cout << "I love China" << endl;

    return 0;
}
  • 类对象作为线程入口函数(async和deferred)
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

class A
{
public:
    int mythread(int mypar)
    {
        cout << mypar << endl;
        cout << "mythread() start" << "thread_id = " << std::this_thread::get_id() << endl;

        std::chrono::milliseconds dura(5000);
        std::this_thread::sleep_for(dura);

        cout << "mythread() end" << "thread_id = " << std::this_thread::get_id() << endl;

        return 5;
    }
};

int main()
{
    A a;
    int tmp_par = 12;

    cout << "main" << "thread_id = " << std::this_thread::get_id() << endl;
    std::future result = std::async(std::launch::async, &A::mythread, &a, tmp_par);
    cout << "continue...!" << endl;

    int def; 
    def = 0;

    cout << result.get() << endl;
    cout << "I love China" << endl;

    return 0;
}
  • package_task
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

int mythread(int mypar)
{
    cout << mypar << endl;
    cout << "mythread() start" << "thread_id = " << std::this_thread::get_id() << endl;

    std::chrono::milliseconds dura(5000);
    std::this_thread::sleep_for(dura);

    cout << "mythread() end" << "thread_id = " << std::this_thread::get_id() << endl;

    return 5;
}

int main()
{
    cout << "main" << "thread_id = " << std::this_thread::get_id() << endl;

    std::packaged_task mypt(mythread);    
    std::thread t1(std::ref(mypt), 1);
    t1.join();
    std::future result = mypt.get_future();
    cout << result.get() << endl;
    cout << "I love China!" << endl;

    return 0;
}
  • packaged_task直接调用

int main()
{
    cout << "main" << "thread_id = " << std::this_thread::get_id() << endl;

    std::packaged_task mypt([](int mypar)
        {
            cout << mypar << endl;
            cout << "mythread() start" << "thread_id = " << std::this_thread::get_id() << endl;

            std::chrono::milliseconds dura(5000);
            std::this_thread::sleep_for(dura);

            cout << "mythread() end" << "thread_id = " << std::this_thread::get_id() << endl;

            return 5;
        }
    );

    // 直接调用,相当于函数调用,是同一个线程。
    mypt(105);

    std::future result = mypt.get_future();
    cout << result.get() << endl;
    cout << "I love China!" << endl;

    return 0;
}
  • 使用了移动语义(move)

vector > mytasks;

int main()
{
    cout << "main" << "thread_id = " << std::this_thread::get_id() << endl;

    std::packaged_task mypt([](int mypar)
        {
            cout << mypar << endl;
            cout << "mythread() start" << "thread_id = " << std::this_thread::get_id() << endl;

            std::chrono::milliseconds dura(5000);
            std::this_thread::sleep_for(dura);

            cout << "mythread() end" << "thread_id = " << std::this_thread::get_id() << endl;

            return 5;
        }
    );

    mytasks.push_back(std::move(mypt)); // 这里使用了move移动语义,而不是拷贝
                                        // 移入之后,mypt就为空了
    
    return 0;
}
  • future和promise
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

void mythread(std::promise& tmpp, int calc)
{
    calc ++;
    calc *= 10;

    std::chrono::milliseconds dura(5000);
    std::this_thread::sleep_for(dura);

    int result = calc;
    tmpp.set_value(result); // 将结果保存到tmpp这个对象中
}

int main()
{
    cout << "main" << "thread_id = " << std::this_thread::get_id() << endl;

    // 声明一个std::promise对象myprom,保存值的类型为int
    std::promise myprom;

    // 使用thread的话,一定要用join(),不然会报异常
    std::thread t1(mythread, std::ref(myprom), 180);
    t1.join();

    // 将promise和future绑定,用于获取线程返回值
    std::future fu1 = myprom.get_future();
    auto result = fu1.get(); // get就是可以得到线程结果

    // 通过promist保存一个值(set_value()),在将来的某个时刻通过
    // 把一个future绑定到promise上得到之前存的值
    cout << "result = " << result << endl;
    cout << "I Love China!" << endl;
    
    return 0;
}
  • 通过future和promise实现thread1和thread2的消息传递
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

void mythread(std::promise& tmpp, int calc)
{
    calc ++;
    calc *= 10;

    std::chrono::milliseconds dura(5000);
    std::this_thread::sleep_for(dura);

    int result = calc;
    tmpp.set_value(result); // 将结果保存到tmpp这个对象中
}

void mythread2(std::future &tmpf)
{
    auto result = tmpf.get();
    cout << "mythread2 result" << result << endl;
    return;
}

int main()
{
    cout << "main" << "thread_id = " << std::this_thread::get_id() << endl;

    // 声明一个std::promise对象myprom,保存值的类型为int
    std::promise myprom;

    // 使用thread的话,一定要用join(),不然会报异常
    std::thread t1(mythread, std::ref(myprom), 180);
    t1.join();

    // 将promise和future绑定,用于获取线程返回值
    std::future fu1 = myprom.get_future();
    
    std::thread t2(mythread2, std::ref(fu1));
    t2.join(); // 等待mythread2线程执行完毕

    cout << "I Love China!" << endl;
    
    return 0;
}

你可能感兴趣的:(并发编程9——async、future,promise,packaged_task)