On C++11 Thread Library

Source: Internet
Author: User

One of the most important features of C++11 is the support of multithreading, but "C + + Primer" 5th does not have this part of the introduction, it is a bit regrettable. Learned something about the thread library on the web. Here are a few of the more good resources to learn 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!

Top two sites I still like very much, are online Help manual, two choose one of them can, see your taste choice is good. The last one is the original "C + + Concurrency in action", a very good book, in view of the Chinese translation version has been black, so can read English version of it, I also bite the bullet to bite a bit. Here are some of the feelings and insights I learned from the thread library, and I would be grateful if you had found my mistake and asked you to criticize it in time.

I don't waste space on the basics of threading and concurrency.

A simple demo that uses threads

C++11 provides a new header file <thread> provides a declaration of support for thread functions (other data protection related declarations are placed in other header files, temporarily starting with the thread header file), and writing a multithreaded program needs to refer to 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;}

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

A New thread! Main thread!

So we can guess that its execution flow is roughly the same:

So how does the execution flow of the program go from main () to the fun (), let's take a look at the thread class first.

Thread Start-up

My environment is CentOS7 + g++4.8.3 header file/usr/include/c++/4.8.3/thread has the full declaration of the thread class (my Windows environment is win8.1+vs2013, In the case of the default installation, the path to the thread header file is C:\Program files (x86) \microsoft Visual Studio 12.0\vc\include\thread). The code is too long and I won't post it. C + + line libraries starts a thread by constructing a thread object . So let's take a look at the thread's constructor:

The following code to post the thread class is from the GNU implementation version

Class thread{. Public    :    thread () noexcept = default;    Thread (thread&) = delete;    Thread (const thread&) = delete;    Thread (thread&& __t) noexcept    {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, but there is a lot of content about c++11 features, rvalue references, noexcept, =delete, and callable objects these are not the points to be concerned about this blog, so it is not detailed to expand. We mainly look at this constructor template,

Template<typename _callable, TypeName ... _args>
Explicit thread (_callable&& __f, _args&& .... __args);

It is clear to see that it has given the parameters to Std::__bind_simple (), and for the definition of std::__bind_simple () in its header file <functional>, and the use of Std::bind (), Specific differences suggest or look at the header file is better, here I have a number of things, conveniently posted out:

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) ...); 

Skill Limited std::bind () concrete implementation I'm not going to go into it, I have a chance to study. However, it is not difficult to see that the function of these two functions is basically to encapsulate a function and its parameters, returning a __type class. When thread constructs a new object, it passes in a __type object to the _m_start_thread () implementation to start a thread. Why did you do it? We can assume that this is due to the implementation of the OS (I also heard on the Internet, if you know the answer, you might as well tell me), using a line on Linux libraries Pthread should have an impression on the Start_routine parameter in Pthread_create (), which is a function pointer, Its corresponding function prototype is as follows:

void* (*start_routine) (void*);

This narrows the difference between the two, and the rest is just a matter of passing in the __type address. Because of this implementation, Std::thread () creates a new thread that can accept arbitrary callable object types (with or without parameters), including lambda expressions (with or without variables), functions, function objects, and function pointers.

We've written a demo with no parameters, and now we're going to create a lambda expression with parameters and captures to see if this is really the case, demo:

#include <thread> #include <iostream>int main () {    int n1 = $;    int n2 = +;    Std::thread t ([&] (int addnum) {        N1 + = Addnum;        N2 + = Addnum;    },500);    T.join ();    Std::cout << N1 << ' << n2 << Std::endl;}

The expected results were obtained:

[thread]main1000 1100
Thread End

After starting a thread (creating a Thread object), when the thread ends (Std::terminate ()), how do we recycle the resources used by the thread? The thread library gives us two options: 1. Join (Join ()) 2. Split (Detach ()). It is worth mentioning that you have to thread make a choice before the object is destroyed, because the thread may have ended before you joined or detached the thread, and then if you detach it, the thread may thread continue to run after the object is destroyed.

Note This decision before the Std::thread object was destroyed-the thread itself may well has F Inished long before you join with it or detach it, and if you detach it,then the thread could continue running long after th E Std::thread object is destroyed.-------"C + + Concurrency in action" 2.1.1

Join () literally means to connect a thread, meaning to actively wait for the thread to terminate, the example above I have used the join () way. Join () works as a join () in the calling process, and when the new thread terminates, the join () cleans up the associated resource (any storage associated with the thread), then returns, and the calling thread continues to execute down. It is because join () cleans up the thread's related resources that our previous thread object has nothing to do with the destroyed thread, which means that the object of a thread can only use one join at a time (), and joinable () will return false after you call the join (). The text is still slightly pale, and certainly the code is 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 ';}

Operation Result:

[Thread]mainbefore Joining,joinable=trueafter joining, Joinable=false

The second way is the split, and the corresponding function is detach (). The meaning of the word detach is the meaning of separation, the use of detach () on a thread object means that the new thread is separated from the calling thread, and we call the disconnected thread called the daemon thread (daemon threads). You can no longer interact with this thread. Make an inappropriate analogy, like you broke up with your girlfriend (you might say I'm good or bad, why don't you say it's me and my girlfriend?) Because I don't have a girlfriend, haha, see how witty I am. After that, you will not have any contact (interaction), and her subsequent consumption of resources will not need you to pay the bill (cleanup resources). Since there is no interaction, there is no join (), so calling joinable () must return FALSE. Detached threads run in the background, with ownership (ownership) and control over the C + + runtime. At the same time, the C + + runtime guarantees that when a thread exits, its associated resources can be properly recycled.

The disconnected thread, which is roughly executed, is no longer required to notify the thread that called it after it has finished running:

The identifier of the thread

In the thread class there is a private variable called _m_id that identifies the thread, and its type is std::thread::id, which is implemented on GNU as follows:

class thread{... class ID {native_handle_type_m_thread; Public:id () Noexcept: _m_thread () {} explicit ID (Native_handle_type __id): _m_thread (__id) {} Priva      Te:friend class thread;      Friend Class hash<thread::id>; friend bool operator== (Thread::id __x, Thread::id __y) noexcept {return __gthread_equal (__x._m_thread, __y._m_t Hread); } friend bool operator< (Thread::id __x, Thread::id __y) noexcept {return __x._m_thread < __y._m_thre Ad } 
Template<class _chart, class _traits> friend Basic_ostream<_chart, _traits>& op erator<< (Basic_ostream<_chart, _traits>& __out, Thread::id __id); };p rivate:id_m_id;public:thread::id get_id () const noexcept {return _m_id; } ...};

The code is clear, and obviously we can get the thread identifier through the std::this_thread::get_id () function, because the Thread::id class overloads the operator "<<" operator in the code above. So we can output the ID type. At the same time, when a thread object is not associated with a threads (perhaps the thread object is the default initialized or the initialized threads have run end by join () or the thread has detach ()), then get_id () will return the default constructed ID object. This means that there is no associated thread for this thread object, and the output might look 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, and the method is straightforward to call std::this_thread::get_id ().

Now, let's write a demo that uses standard output to try out 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 ();}

Its output is a 15-bit integer, depending on the implementation, of course, how the implementation is no different, we just care about it as a way to identify the thread:

[thread]main140302328772352140302328772352

At the same time, Std::thread::id also overloads the operator==, which allows us to compare whether two threads are equal (whether it is the same thread), for example, we need to assign tasks to different threads or restrict the operation of a thread. The ID type implements this comparison operation which gives us great convenience in programming.

As to when to use the std::thread::id::operator<, I am not clear, if you know, may wish to tell me, I will be extremely grateful.

Understanding the above, we can basically use multi-threaded to achieve some simple tasks, of course, want to use the thread safely, this is far from enough. And then I'm going to go back and explore the thread library.

If the above blog is wrong, misleading, please forgive, but also hope to criticize, I thank you first.

On C++11 Thread Library

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.