【C++标准库】并发

高级接口async()和future

/* The following code example is taken from the book
* "The C++ Standard Library - A Tutorial and Reference, 2nd Edition"
* by Nicolai M. Josuttis, Addison-Wesley, 2012
*
* (C) Copyright Nicolai M. Josuttis 2012.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
#include <future>
#include <thread>
#include <chrono>
#include <random>
#include <iostream>
#include <exception>
using namespace std;

int doSomething(char c)
{
    // random-number generator (use c as seed to get different sequences)
    std::default_random_engine dre(c);
    std::uniform_int_distribution<int> id(10, 1000);

    // loop to print character after a random period of time
    for (int i = 0; i<10; ++i) 
    {
        this_thread::sleep_for(chrono::milliseconds(id(dre)));
        cout.put(c).flush();
    }

    return c;
}

int func1()
{
    return doSomething('.');
}

int func2()
{
    return doSomething('+');
}

int main()
{
    std::cout << "starting func1() in background"
        << " and func2() in foreground:" << std::endl;

    // start func1() asynchronously (now or later or never):
    std::future<int> result1(std::async(func1));

    int result2 = func2();    // call func2() synchronously (here and now)

    // print result (wait for func1() to finish and add its result to result2
    int result = result1.get() + result2;

    std::cout << "\nresult of func1()+func2(): " << result
        << std::endl;
}

class std::future提供了“处理并发运算之未来结果”的能力,但是get()只能调用一次,第二次调用get()会导致不可预期的行为。然而有时候,多次处理并发结果是合理的,特别是当多个线程都想处理这个结果时。基于这个目的,C++标准库提供了class std::shared_future,可以多次调用get(),得到相同的结果,或导致抛出一个异常。

/* The following code example is taken from the book
* "The C++ Standard Library - A Tutorial and Reference, 2nd Edition"
* by Nicolai M. Josuttis, Addison-Wesley, 2012
*
* (C) Copyright Nicolai M. Josuttis 2012.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
#include <future>
#include <thread>
#include <iostream>
#include <exception>
#include <stdexcept>
using namespace std;

int queryNumber()
{
    // read number
    cout << "read number: ";
    int num;
    cin >> num;

    // throw exception if none
    if (!cin) {
        throw runtime_error("no number read");
    }

    return num;
}

void doSomething(char c, shared_future<int> f)
{
    try 
    {
        // wait for number of characters to print
        int num = f.get();  // get result of queryNumber()

        for (int i = 0; i<num; ++i) 
        {
            this_thread::sleep_for(chrono::milliseconds(100));
            cout.put(c).flush();
        }
    }
    catch (const exception& e)
    {
        cerr << "EXCEPTION in thread " << this_thread::get_id()
            << ": " << e.what() << endl;
    }
}

int main()
{
    try 
    {
        // start one thread to query a number
        shared_future<int> f = async(queryNumber);

        // start three threads each processing this number in a loop
        auto f1 = async(launch::async, doSomething, '.', f);
        auto f2 = async(launch::async, doSomething, '+', f);
        auto f3 = async(launch::async, doSomething, '*', f);

        // wait for all loops to be finished
        f1.get();
        f2.get();
        f3.get();
    }
    catch (const exception& e) 
    {
        cout << "\nEXCEPTION: " << e.what() << endl;
    }
    cout << "\ndone" << endl;
}
View Code

低层接口:Thread和Promise

/* The following code example is taken from the book
* "The C++ Standard Library - A Tutorial and Reference, 2nd Edition"
* by Nicolai M. Josuttis, Addison-Wesley, 2012
*
* (C) Copyright Nicolai M. Josuttis 2012.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
#include <thread>
#include <chrono>
#include <random>
#include <iostream>
#include <exception>
using namespace std;

void doSomething(int num, char c)
{
    try 
    {
        // random-number generator (use c as seed to get different sequences)
        default_random_engine dre(42 * c);
        uniform_int_distribution<int> id(10, 1000);
        for (int i = 0; i<num; ++i) 
        {
            this_thread::sleep_for(chrono::milliseconds(id(dre)));
            cout.put(c).flush();
            //...
        }
    }
    // make sure no exception leaves the thread and terminates the program
    catch (const exception& e) {
        cerr << "THREAD-EXCEPTION (thread "
            << this_thread::get_id() << "): " << e.what() << endl;
    }
    catch (...) {
        cerr << "THREAD-EXCEPTION (thread "
            << this_thread::get_id() << ")" << endl;
    }
}

int main()
{
    try 
    {
        thread t1(doSomething, 5, '.');  // print five dots in separate thread
        cout << "- started fg thread " << t1.get_id() << endl;

        // print other characters in other background threads
        for (int i = 0; i<5; ++i) {
            thread t(doSomething, 10, 'a' + i); // print 10 chars in separate thread
            cout << "- detach started bg thread " << t.get_id() << endl;
            t.detach();  // detach thread into the background
        }

        cin.get();  // wait for any input (return)

        cout << "- join fg thread " << t1.get_id() << endl;
        t1.join();  // wait for t1 to finish
    }
    catch (const exception& e) {
        cerr << "EXCEPTION: " << e.what() << endl;
    }
}

/* The following code example is taken from the book
* "The C++ Standard Library - A Tutorial and Reference, 2nd Edition"
* by Nicolai M. Josuttis, Addison-Wesley, 2012
*
* (C) Copyright Nicolai M. Josuttis 2012.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
#include <thread>
#include <future>
#include <iostream>
#include <string>
#include <exception>
#include <stdexcept>
#include <functional>
#include <utility>

void doSomething(std::promise<std::string>& p)
{
    try {
        // read character and throw exception if 'x'
        std::cout << "read char ('x' for exception): ";
        char c = std::cin.get();
        if (c == 'x') {
            throw std::runtime_error(std::string("char ") + c + " read");
        }
        //...
        std::string s = std::string("char ") + c + " processed";
        p.set_value_at_thread_exit(std::move(s));    // store result
    }
    catch (...) {
        p.set_exception_at_thread_exit(std::current_exception());  // store exception
    }
}

int main()
{
    try 
    {
        // create a promise to store the outcome
        std::promise<std::string> p;
        // create a future to process the outcome
        std::future<std::string> f(p.get_future());
        // start a thread using the promise to store the outcome
        std::thread t(doSomething, std::ref(p));
        t.detach();
        //...

        // process the outcome
        std::cout << "result: " << f.get() << std::endl;
    }
    catch (const std::exception& e) 
    {
        std::cerr << "EXCEPTION: " << e.what() << std::endl;
    }
    catch (...) 
    {
        std::cerr << "EXCEPTION " << std::endl;
    }
}

 

posted @ 2018-08-22 19:42  summer91  阅读(402)  评论(0编辑  收藏  举报