简体   繁体   中英

c++ std::thread: Is this code guaranteed to deadlock?

The following code is from modernescpp . I understand that when the lock_guard in the main thread holding the mutex causes the deadlock. But since the created thread should start to run once it is initialized. Is there a chance that after line 15 the functions lock_guard on line 11 already grabbed coutMutex so the code runs without any problem? If it is possible, under what circumstance the created thread will run first?

#include <iostream>
#include <mutex>
#include <thread>

std::mutex coutMutex;

int main(){

  std::thread t([]{
    std::cout << "Still waiting ..." << std::endl;
    std::lock_guard<std::mutex> lockGuard(coutMutex); // Line 11
    std::cout << std::this_thread::get_id() << std::endl;
    }
  );
  // Line 15
  {
    std::lock_guard<std::mutex> lockGuard(coutMutex);
    std::cout << std::this_thread::get_id() << std::endl;
    t.join();
  }
}

Just so the answer will be posted as an answer, not a comment:

  • No, this code is not guaranteed to deadlock.
  • Yes, this code is quite likely to deadlock.

In particular, it's possible for the main thread to create the subordinate thread, and then both get suspended. From that point, it's up to the OS scheduler to decide which to run next. Since the main thread was run more recently, there's a decent chance it will select the subordinate thread to run next (assuming it attempts to follow something vaguely like round-robin scheduling in the absence of a difference in priority, or something similar giving it a preference for which thread to schedule).

There are various ways to fix the possibility of deadlock. One obvious possibility would be to move the join to just outside the scope in which the main thread holds the mutex:

#include <iostream>
#include <mutex>
#include <thread>

std::mutex coutMutex;

int main(){

  std::thread t([]{
    std::cout << "Still waiting ..." << std::endl;
    std::lock_guard<std::mutex> lockGuard(coutMutex); // Line 11
    std::cout << std::this_thread::get_id() << std::endl;
    }
  );
  // Line 15
  {
    std::lock_guard<std::mutex> lockGuard(coutMutex);
    std::cout << std::this_thread::get_id() << std::endl;
  }
  t.join();
}

I'd also avoid locking a mutex for the duration of using std::cout . cout is typically slow enough that doing so will make contention over the lock quite likely. It's typically doing to be better to (for only one example) format the data into a buffer, put the buffer into a queue, and have a single thread that reads items from the queue and shoves them out to cout . This way you only have to lock for long enough to add/remove a buffer to/from the queue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM