For the use of multithreading, this paper briefly introduces several ways of using multithreading, and uses several simple examples to introduce multithreading. The compiler is visual studio.
1, AsyncFuture
The knowledge points used are std::async and std::future
1. std::async function prototype
template<class Fn, class... Args> future<typename result_of<Fn(Args...)>::type> async(launch policy, Fn&& fn, Args&&...args);
Function: the second parameter receives a callable object (imitation function, lambda expression, class member function, ordinary function...) As parameters, and execute them asynchronously or synchronously.
Whether to execute asynchronously or synchronously depends on the execution policy of the first parameter:
(1) The callable object passed by std::launch::async executes asynchronously;
(2) std::launch::deferred: the callable objects passed are executed synchronously;
(3) std::launch::async | std::launch::deferred can be asynchronous or synchronous, depending on the operating system, which is beyond our control;
(4) If no specific policy is specified, it will be executed by default (3).
If an asynchronous execution policy is selected, when get is called, if the asynchronous execution is not finished, get blocks the current calling thread until the end of asynchronous execution ends and gets the result. If the asynchronous execution is finished, it does not wait to get the execution result; If the synchronous execution strategy is selected, the synchronous call is actually executed only when the get function is called, which is also called function call delay.
Status of returned result std::future:
(1) deffered: the asynchronous operation has not started yet;
(2) ready: the asynchronous operation has been completed;
(3) timeout: the asynchronous operation timed out.
example
#include "stdfax.h" /* std::async,std::future */ int main() { // step1 possibly start thread immediately std::future<int> ft1(std::async(sum, 1, 11)); std::future<int> ft2(std::async(sum, 1, 101)); try { // step2 to get result we have to call future.get() int a = ft1.get(); int b = ft2.get(); cout << a << " + " << b << " = " << a + b << endl; } catch (std::exception& e) { cout << e.what() << endl; } return 0; }
2, PackageTaks
The knowledge points used are std::package_task and std::future
1,std::package_task is a template class
std::packaged_task wraps any callable object (function, lambda expression, bind expression, function object) so that it can be called asynchronously. Its return value or thrown exception is stored in a shared state that can be accessed through the std::future object.
example
#include "stdfax.h" /* std::package_task, std::promise,std::future */ int main() { // step 1 does not start thread yet std::packaged_task<int(int, int)> task1(sum); std::packaged_task<int(int, int)> task2(sum); // step2 create future using task std::future<int> ft1 = task1.get_future(); std::future<int> ft2 = task2.get_future(); // step3 we have to start the thread // start the task (or thread) task1(1, 11); task2(1, 101); try { // step 4 now get the result of processing int a = ft1.get(); int b = ft2.get(); cout << a << " + " << b << " = " << a + b << endl; } catch (std::exception& e) { cout << e.what() << endl; } }
3, Promise future
The knowledge points used are std::thread, std::promise and std::future
1,std::future
std::future expects a return. From the perspective of an asynchronous call, future is more like the return value of an executing function. The C + + standard library uses std::future to model a one-time event. If an event needs to wait for a specific one-time event, the thread can obtain a future object to represent the event. Asynchronous calls often do not know when to return, but if the process of asynchronous calls needs to be synchronized, or the latter asynchronous call needs to use the result of the previous asynchronous call. The future will be used at this time.
2,std::promise
Promise object can store the value of a certain type of T, which can be read by the future object (possibly in another program). Therefore, promise also provides a means of thread synchronization. During the construction of promise object, it can be associated with a shared state (usually std::future), and a value of type T can be saved on the associated shared state (std::future).
You can use get_future to obtain the future object associated with the promise object. After calling this function, the two objects share the same shared state
- promise object is an asynchronous Provider, which can set the value of sharing state at a certain time.
- The future object can return the value of the shared state asynchronously, or block the caller if necessary and wait for the shared state flag to change to ready before obtaining the value of the shared state.
get_future()
This function returns a future associated with promise shared state. The returned future object can access the value set in the shared state by the promise object or an exception object. Only one future object can be obtained from promise shared state. After calling this function, the promise object is usually ready at a certain point in time (set a value or an exception object). If the value or exception is not set, the promise object will automatically set a future when destructing_ Error exception (broken_promise) to set its own preparation state.
example
#include "stdfax.h" /* std:thread,std::promise,std:future */ int main() { // step 1 create a promise with return type std::promise<int> prm,prm2; // step 2 create a future using the promise std::future<int> ft = prm.get_future(); std::future<int> ft2 = prm2.get_future(); // step 3 create a thread using promise std::thread thr(sum_prm, std::ref(prm), 1, 11); std::thread thr2(sum_prm, std::ref(prm2), 1, 101); // step 4 detach thread // you should not forget this step thr.detach(); thr2.detach(); try { // step 5 now get the result of processing int a = ft.get(); int b = ft2.get(); cout << a << " + " << b << " = " << a + b << endl; } catch (std::exception& e) { cout << e.what() << endl; } return 0; }
General code of zero and example
stdafx.h
#include <stdio.h> #include <tchar.h> #include "thread_inc.h"
stdafx.cpp
#include "stdfax.h" #include "thread_inc.cpp"
thread_inc.h
#include <iostream> #include <thread> #include <memory> #include <future> #include <functional> #include <utility> #include <exception> #include <sstream> using namespace std; extern int sum(int st, int ed); extern void sum_prm(std::promise<int>& prm, int st, int ed);
thread_inc.cpp the code of this file does not participate in the generation. Click thread_inc.cpp, right-click the attribute, and in general - item type, set not to participate in generation.
int sum(int st, int ed) { int rlt = 0; for (int i = st; i < ed; ++i) { // Setting exception if (i == (st + ed) / 2) { std::ostringstream os; os << "sum(" <<st<< ", " << ed << ") - throw exception at: " << i; throw std::runtime_error(os.str().c_str()); } rlt += i; } return rlt; } void sum_prm(std::promise<int>& prm, int st, int ed) { int rlt = 0; try { for (int i = st; i < ed; ++i) { // Setting exception if (i == (st + ed) / 2) { std::ostringstream os; os << "sum_prm(" << st << ", " << ed << ") - throw exception at: " << i; throw std::runtime_error(os.str().c_str()); } rlt += i; } // prm.set_value(rlt); prm.set_value_at_thread_exit(rlt); } catch (std::exception& e) { //prm.set_exception(std::current_exception() ) prm.set_exception_at_thread_exit(std::current_exception()); } }