2.1 Basic thread management
2.1.1 Launching a thread
void do_some_work(); std::thread my_thread(do_some_work);
class background_task { public: void operator()() const { do_something(); do_something_else(); } }; background_task f; std::thread my_thread(f);
std::thread my_thread(background_task());
std::thread my_thread((background_task())); std::thread my_thread{background_task()};
If you don’t wait for your thread to finish, then you need to ensure that the data accessed by the thread is valid until the thread has finished with it.
struct func { int& i; func(int& i_):i(i_){} void operator()() { for(unsigned j=0;j<1000000;++j) { do_something(i); } } }; void oops() { int some_local_state=0; func my_func(some_local_state); std::thread my_thread(my_func); my_thread.detach(); }
2.1.2 Waiting for a thread to complete
If you need to wait for a thread to complete, you can do this by calling join() on the associated std::thread instance. join() is simple and brute force—either you wait for a thread to finish or you
don’t.
2.1.3 Waiting in exceptional circumstances
struct func; void f() { int some_local_state=0; func my_func(some_local_state); std::thread t(my_func); try { do_something_in_current_thread(); } catch(...) { t.join(); throw; } t.join(); }
class thread_guard { std::thread& t; public: explicit thread_guard(std::thread& t_): t(t_) {} ~thread_guard() { if(t.joinable()) { t.join(); } } thread_guard(thread_guard const&)=delete; thread_guard& operator=(thread_guard const&)=delete; }; struct func; void f() { int some_local_state=0; func my_func(some_local_state); std::thread t(my_func); thread_guard g(t); do_something_in_current_thread(); }One way of doing this is to use the standard Resource Acquisition Is Initialization (RAII) idiom and provide a class that does the join() in its destructor.
2.1.4 Running threads in the background
Calling detach() on a std::thread object leaves the thread to run in the background, with no direct means of communicating with it. It’s no longer possible to wait for that thread to complete; if a thread becomes detached, it isn’t possible to obtain a std::thread object that references it, so it can no longer be joined. Detached threads truly run in the background; ownership and control are passed over to the C++ Runtime Library, which ensures that the resources associated with the thread are correctly reclaimed when the thread exits.
void edit_document(std::string const& filename) { open_document_and_display_gui(filename); while(!done_editing()) { user_command cmd=get_user_input(); if(cmd.type==open_new_document) { std::string const new_name=get_filename_from_user(); std::thread t(edit_document,new_name); t.detach(); } else { process_user_input(cmd); } } }
2.2 Passing arguments to a thread function
void f(int i,std::string const& s); std::thread t(f,3,”hello”);传参的基本方法。
void f(int i,std::string const& s); void oops(int some_param) { char buffer[1024]; sprintf(buffer, "%i",some_param); std::thread t(f,3,buffer); t.detach(); }
void f(int i,std::string const& s); void not_oops(int some_param) { char buffer[1024]; sprintf(buffer,"%i",some_param); std::thread t(f,3,std::string(buffer)); t.detach(); }
void update_data_for_widget(widget_id w,widget_data& data); void oops_again(widget_id w) { widget_data data; std::thread t(update_data_for_widget,w,data); display_status(); t.join(); process_widget_data(data); }
void update_data_for_widget(widget_id w,widget_data& data); void oops_again(widget_id w) { widget_data data; std::thread t(update_data_for_widget,w,std::ref(data)); display_status(); t.join(); process_widget_data(data); }
An example of such a type is std::unique_ptr , which provides automatic memory management for dynamically allocated objects. Only one std::unique_ptr instance can point to a given object at
a time, and when that instance is destroyed, the pointed-to object is deleted. The move constructor and move assignment operator allow the ownership of an object to be transferred around between std::unique_ptr instances.
void process_big_object(std::unique_ptr<big_object>); std::unique_ptr<big_object> p(new big_object); p->prepare_data(42); std::thread t(process_big_object,std::move(p));
void some_function(); void some_other_function(); std::thread t1(some_function); std::thread t2=std::move(t1); t1=std::thread(some_other_function); std::thread t3; t3=std::move(t2); t1=std::move(t3);
std::thread f() { void some_function(); return std::thread(some_function); } std::thread g() { void some_other_function(int); std::thread t(some_other_function,42); return t; }
class scoped_thread { std::thread t; public: explicit scoped_thread(std::thread t_): t(std::move(t_)) { if(!t.joinable()) throw std::logic_error(“No thread”); } ~scoped_thread() { t.join(); } scoped_thread(scoped_thread const&)=delete; scoped_thread& operator=(scoped_thread const&)=delete; }; struct func; void f() { int some_local_state; scoped_thread t(std::thread(func(some_local_state))); do_something_in_current_thread(); }
void do_work(unsigned id); void f() { std::vector<std::thread> threads; for(unsigned i=0;i<20;++i) { threads.push_back(std::thread(do_work,i)); } std::for_each(threads.begin(),threads.end(), std::mem_fn(&s
2.4 Choosing the number of threads at runtime
One feature of the C++ Standard Library that helps here is std::thread::hardware_concurrency() . This function returns an indication of the number of threads that can truly run concurrently for a given
execution of a program.
template<typename Iterator,typename T> struct accumulate_block { void operator()(Iterator first,Iterator last,T& result) { result=std::accumulate(first,last,result); } }; template<typename Iterator,typename T> T parallel_accumulate(Iterator first,Iterator last,T init) { unsigned long const length=std::distance(first,last); if(!length) return init; unsigned long const min_per_thread=25; unsigned long const max_threads= (length+min_per_thread-1)/min_per_thread; unsigned long const hardware_threads= std::thread::hardware_concurrency(); unsigned long const num_threads= std::min(hardware_threads!=0?hardware_threads:2,max_threads); unsigned long const block_size=length/num_threads; std::vector<T> results(num_threads); std::vector<std::thread> threads(num_threads-1); Iterator block_start=first; for(unsigned long i=0;i<(num_threads-1);++i) { Iterator block_end=block_start; std::advance(block_end,block_size); threads[i]=std::thread( accumulate_block<Iterator,T>(), block_start,block_end,std::ref(results[i])); block_start=block_end; } accumulate_block<Iterator,T>()( block_start,last,results[num_threads-1]); std::for_each(threads.begin(),threads.end(), std::mem_fn(&std::thread::join)); return std::accumulate(results.begin(),results.end(),init); }上面这段程序进行求和运算,根据数据范围以及机器能够支持的线程数量,进行创建合适的线程数目。
2.5 Identifying threads
Thread identifiers are of type std::thread::id and can be retrieved in two ways. First, the identifier for a thread can be obtained from its associated std::thread object by calling the
get_id() member function. If the std::thread object doesn’t have an associated thread of execution, the call to get_id() returns a default-constructed std::thread::id object, which indicates “not any thread.” Alternatively, the identifier
for the current thread can be obtained by calling std::this_thread::
get_id() , which is also defined in the <thread> header.
2.6 Summary
In this chapter I covered the basics of thread management with the C++ Standard Library: starting threads, waiting for them to finish, and not waiting for them to finish because you want them
to run in the background. You also saw how to pass arguments into the thread function when a thread is started, how to transfer the responsibility for managing a thread from one part of the code to another, and how groups of threads can be used to divide work.
Finally, I discussed identifying threads in order to associate data or behavior with specific threads that’s inconvenient to associate through alternative means. Although you can do quite a lot with purely independent threads that each operate on
separate data, as in listing 2.8 for example, sometimes it’s desirable to share data among threads while they’re running. Chapter 3 discusses the issues surrounding sharing data directly among threads, while chapter 4 covers more general issues
surrounding synchronizing operations with and without shared data.
Chapter2 Managing threads,布布扣,bubuko.com
原文:http://blog.csdn.net/ict2014/article/details/22891117