C + + concurrent (CH02)[Launching a thread-01]

Keywords: Lambda

Launching a thread

All callable objects can be used as parameters of 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);

There is a problem with the following statement

std::thread my_thread(background_task());

It is a function whose name is my thread and return value is h dead std::thread
The parameter of a function is a function pointer that does not return a parameter, so it is better to use the following declaration form

std::thread my_thread((background_task()));
std::thread my_thread{background_task()}; 

How to declare a thread variable without running it. You can also use lambda expressions

std::thread my_thread([]{
                          do_something();
                          do_something_else();
                      });
  1. Note that if you do not detach and join threads, the thread will be terminate d after the main thread exits

  2. If you detach a thread, the thread may run for a long time even after the thread object is destroyed. The thread object is only the object used by C + + to manage the computer thread. If you detach it, the object can be released and destroyed naturally. But the computer thread is still running on the computer

If you bring local variables into thread, undefined behaviors will occur. Don't make mistakes

struct func
{
    int& i;
    func(int& i_):i(i_){}
    void operator()()
    {
        for(unsigned j=0;j<1000000;++j)
        {
            do_something(i);                // 1. Potential access to dangling
        }
    }
};
void oops()
{
    int some_local_state=0;
    func my_func(some_local_state);
    std::thread my_thread(my_func);
    my_thread.detach();                    // 2. Don't wait for thread to finish
}                                          // 3. New thread might still be running

If the thread parameter is a callable object, its variables are copied. However, if there are pointers and references in it, it cannot be avoided to access the area of the released resources. So we should also be careful not to let this happen

Wait for the thread to end

You can only call join once. Whether you call join of thread or detach. At this time, join() of thread will return false. You can only operate join once
or detach.

Facing exceptions: the time to call join should be considered, because the main thread may have exceptions. You will not have the chance to join a thread or detach a thread

struct func;    // <-- See definition in listing 2.1
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(); // <-- 1

      throw;
    }
  t.join();     // <-- 2
}

This is not a good way to deal with it. try and
If you catch, it's hard to ensure that all exceptions are taken into account. Therefore, you should use the RAII method (Resource
Acquisition Is Initialization)

class thread_guard
{
  std::thread& t;
public:
  explicit thread_guard(std::thread& t_):
    t(t_)
  {}
  ~thread_guard()
  {
    if(t.joinable())                        // <-- 1
      {
        t.join();                           // <-- 2
      }
  }
  thread_guard(thread_guard const&)=delete; // <-- 3
  thread_guard& operator=(thread_guard const&)=delete;
};
struct func;                                // <-- See definition in listing 2.1
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();
}                                           // <-- 4

=delete=delete=delete
The compiler is prohibited from providing default functions, such as the default copy constructor and copy constructor. Copying these objects will cause compiler errors

Let thread run in the background

  1. Once a thread is detach ed, it will be taken over by the C++ Runtime Library. The user cannot pass the thread
    Object join and control
std::thread t(do_background_work);
t.detach();
assert(!t.joinable());

If t.joinable() returns false, it cannot be detach

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); //<--1
          //(sai: a form of passing parameters, which can also be called object with member data in it)
          t.detach();                            //<--2
        }
      else
        {
          process_user_input(cmd);
        }
    }
}

Be careful
Although you detach, the main thread exits. All your threads will also be terminate d. Therefore, the validity of detach needs to be supported by the main thread. The so-called main thread is your run
The thread of the main function

122 original articles published, praised 11, 10000 visitors+
Private letter follow

Posted by webworks on Sat, 29 Feb 2020 21:15:22 -0800