C ++ 11 Thread Library

Source: Internet
Author: User
Tags traits

C ++ 11 Thread Library

One of the most important features of c ++ 11 is its support for multithreading. However, the 5th section of c ++ primer does not cover this part, which is a pity. I learned about the thread library on the Internet. These are the resources for learning the thread Library:

Thread support library                    : http://en.cppreference.com/w/cpp/thread

Cpp reference/thread                      : http://www.cplusplus.com/reference/thread/

<< C++ Concurrency In Action >>  :http://files.cnblogs.com/files/ittinybird/CplusplusConcurrencyInAction.pdf             //Recommend!

I like the first two websites very much. They are all online help manuals. You can select one of them. You can choose your taste. The last one is the original C ++ Concurrency In Action, a great book. Since the Chinese version has been hacked, you can read the English version, I am also biting my head. The following are my experiences and insights on the thread library,If you find my mistakes, please correct them in time. Thank you very much..

I will not waste space on basic knowledge about threads and concurrency.

A simple Demo of using threads

C ++ 11 provides a new header file <thread> to provide support for thread functions (other data protection-related declarations are placed in other header files, start with the thread header file.) Write a multi-threaded program and reference this new header file:

#include <iostream>#include <thread>void fun(){   std::cout << "A new thread!" << std::endl;}int main(){    std::thread t(fun);    t.join();    std::cout << "Main thread!" << std::endl;}

Such a demo is a simple multi-threaded application. The output is as follows:

A new thread!Main thread!

Therefore, we can guess that the execution stream is roughly like this:

Class thread {... public: thread () notest = default; thread (thread &) = delete; thread (const thread &) = delete; thread (thread & _ t) notest {swap (_ t);} template <typename _ Callable, typename... _ Args> explicit thread (_ Callable & _ f, _ Args &&... _ args) {_ M_start_thread (_ M_make_routine (std: :__ bind_simple (std: forward <_ Callable> (_ f), std :: forward <_ Args> (_ args )...)));}...};

These lines of code have a lot of content related to the c ++ 11 features, the reference of the right value, notest, = delete, and callable objects are not the points of attention in this blog, so they are not detailed. We mainly look at this constructor template,

template<typename _Callable, typename... _Args>
explicit thread(_Callable&& __f, _Args&&... __args);

You can clearly see that it has handed over all the parameters to std :__ bind_simple () for processing, and the definition of std: :__ bind_simple () is in the header file <functional>, the usage of std: bind () is the same as that of std: bind (). It is better to look at the header file for specific differences. Here I will post multiple things as soon as possible:

template<typename _Callable, typename... _Args>typename _Bind_simple_helper<_Callable, _Args...>::__type__bind_simple(_Callable&& __callable, _Args&&... __args){    typedef _Bind_simple_helper<_Callable, _Args...> __helper_type;    typedef typename __helper_type::__maybe_type __maybe_type;    typedef typename __helper_type::__type __result_type;    return __result_type(        __maybe_type::__do_wrap( std::forward<_Callable>(__callable)),        std::forward<_Args>(__args)...);}   template<typename _Result, typename _Func, typename... _BoundArgs>inline typename _Bindres_helper<_Result, _Func, _BoundArgs...>::typebind(_Func&& __f, _BoundArgs&&... __args){    typedef _Bindres_helper<_Result, _Func, _BoundArgs...> __helper_type;    typedef typename __helper_type::__maybe_type __maybe_type;    typedef typename __helper_type::type __result_type;    return __result_type(__maybe_type::__do_wrap(std::forward<_Func>(__f)),   std::forward<_BoundArgs>(__args)...);}

Limited skill std: bind () I will not go deep into the specific implementation. I have the opportunity to study it. But it is easy to see that the two functions basically encapsulate a function and its parameters and return a _ type class. When constructing a new object, thread passes in a _ type object to _ M_start_thread () to start a thread. Why? We can think that this is because of the OS implementation (I also heard it online, if you know the answer, you may wish to tell me), the thread library pthread on Linux should be on pthread_create () the start_routine parameter in is impressive. It is a function pointer and its prototype is as follows:

void* (*start_routine) (void*);

In this way, the difference between the two is reduced, and only the _ type address can be passed in. Due to this implementation, std: thread () can be used to create a new thread.Accept Any callable object type (with or without parameters), including lambda expressions (with variable capture or without parameters), functions, function objects, and function pointers.

We have written a demo without parameters above. Now we will create a lambda expression containing parameters and captured to see if it is like this. demo:

#include <thread>#include <iostream>int main(){    int n1 = 500;    int n2 = 600;    std::thread t([&](int addNum){        n1 += addNum;        n2 += addNum;    },500);    t.join();    std::cout << n1 << ' ' << n2 << std::endl;}

Expected results are displayed:

[thread]main1000 1100
Thread end

After a thread is started (a thread object is created) and the thread ends (std: terminate (), how can we recycle the resources used by the thread? The thread Library provides two options: 1. join () 2. Split (detach ()). It is worth mentioning that you mustthreadMake a choice before the object is destroyed, because the thread may have ended before you add or detach the thread. If you then detach it, the thread maythreadAfter the object is destroyed, it continues to run.

Note that you only have to make this decision before the std::thread object is destroyed—the thread itself may well have finished long before you join with it or detach it, and if you detach it,then the thread may continue running long after the std::thread object is destroyed.-------《C++ Concurrency In Action》 2.1.1

Join () literally means to connect to a thread, which means to actively wait for the termination of the thread. In the above example, I used the join () method. Join () works in this way. When a new thread is terminated during the call process, join () clears related resources (any storage associated with the thread ), then return, and the calling thread continues to execute. It is precisely because join () clears thread-related resources that our previous thread object has nothing to do with the destroyed thread, this means that you can only use join () once for a thread object each time. When you call join (), joinable () returns false. The text is pale, and the Code must be more intuitive:

#include <iostream>#include <thread>void foo(){    std::this_thread::sleep_for(std::chrono::seconds(1));} int main(){    std::thread t(foo);    std::cout << "before joining,joinable=" << std::boolalpha << t.joinable() << std::endl;    t.join();    std::cout << "after joining, joinable=" << std::boolalpha << t.joinable() << '\n';}

Running result:

[thread]mainbefore joining,joinable=trueafter joining, joinable=false

The second method is split, and the corresponding function is detach (). Detach indicates separation. Using detach () for a thread object means that the new thread is recognized from the calling thread. We call the separated thread as the daemon thread (Daemon threads). Then, you cannot interact with this thread. For example, if you break up with your girlfriend (You may say I am good or bad, why not say it's my girlfriend and I? Because I don't have a girlfriend, haha. How witty I am .), After that, you will not have any more contact (interaction), and the various resources consumed after her will not need to be paid for (cleaning up resources ). Since there is no interaction, we cannot talk about join (). Therefore, calling joinable () must return false. The detached thread runs in the background, and its ownership and control will be handed over to the c ++ Runtime Library. At the same time, the C ++ Runtime Library ensures that the relevant resources can be correctly recycled when the thread exits.

A separate thread is executed in this way. After it finishes running, it no longer needs to notify the thread that calls it:

Class thread {... class id {native_handle_type_M_thread; public: id () noexcept: _ M_thread () {} explicit id (native_handle_type _ id): _ M_thread (_ id) {} private: friend class thread; friend class hash <thread: id>; friend bool operator = (thread: id _ x, thread: id _ y) notest {return _ gthread_equal (_ x. _ M_thread, _ y. _ M_thread);} friend bool operator <(thread: id _ x, thread: id _ y) no1_t {return _ x. _ M_thread <_ y. _ M_thread ;}
Template <class _ CharT, class _ Traits> friend basic_ostream <_ CharT, _ Traits> & operator <(basic_ostream <_ CharT, _ Traits> & _ out, thread :: id _ id) ;}; private: id_M_id; public: thread: id get_id () const notest {return _ M_id ;}...};

The code is clear. Obviously, we can use the std: this_thread: get_id () function to obtain the thread identifier :: the operator "<" operator is overloaded in the id class, so we can output the id type. At the same time, when a thread object is not associated with a thread (maybe the thread object is initialized by default, or the initialization thread has been run and ended and is joined () or the thread has been detach ()), at this time, get_id () will return the default constructed id object, which means that this thread object does not have an associated thread, and the output may be like this: "thread: id of a non-executing thread ". At the same time, we can also get the thread identifier of the current thread in the current thread, the method is relatively simple to directly call std: this_thread: get_id.

Now, let's write a demo that uses the standard output to try to output the thread id:

#include <iostream>#include <thread>void fun(){    std::cout << std::this_thread::get_id() << std::endl;}int main(){    std::thread t(fun);    std::cout << t.get_id() << std::endl;    t.join();}

The output result is a 15-digit integer, depending on the implementation. Of course, there is no difference in how to implement it. We only need to care about it as a means to identify the thread:

[thread]main140302328772352140302328772352

At the same time, the std: thread: id also contains operator =, which allows us to compare whether two threads are equal (whether they are the same thread ), for example, if we need to allocate tasks to different threads or restrict operations on a specific thread, the id type achieves such a comparison operation, which greatly facilitates programming.

I am not clear about the time when std: thread: id: operator <is used. If you know it, please let me know. I am very grateful.

 

After understanding the above content, we can basically use multithreading to implement some simple tasks. Of course, it is far from enough to safely use threads. Next I will explore the thread library again.

If any of the above blog posts is incorrect or misleading, please forgive me and hope to criticize and correct me. I would like to thank you first.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.