c ++ std :: thread: этот код гарантированно заблокирован? - PullRequest
0 голосов
/ 21 декабря 2018

Следующий код из modernescpp .Я понимаю, что когда lock_guard в основном потоке, удерживающем мьютекс, вызывает тупик.Но поскольку созданный поток должен начать работать после его инициализации.Есть ли вероятность, что после строки 15 функции lock_guard в строке 11 уже перехватили coutMutex, чтобы код работал без проблем?Если это возможно, при каких обстоятельствах созданный поток будет запускаться первым?

#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();
  }
}

1 Ответ

0 голосов
/ 21 декабря 2018

Просто ответ будет опубликован в виде ответа, а не комментария:

  • Нет, этот код не гарантирован до тупика.
  • Даэтот код вполне вероятен для взаимоблокировки.

В частности, основной поток может создать подчиненный поток, а затем оба будут приостановлены.Начиная с этого момента, планировщик ОС решает, что делать дальше.Так как основной поток был запущен совсем недавно, есть большая вероятность, что он выберет подчиненный поток для запуска в следующем (при условии, что он пытается следовать чему-то неопределенному, например, циклическому планированию при отсутствии разницы в приоритете, или что-то подобное, давая емупредпочтение тому, какой поток запланировать).

Существуют различные способы исправить возможность взаимоблокировки.Одна очевидная возможность состоит в том, чтобы переместить join за пределы области видимости, в которой основной поток содержит мьютекс:

#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();
}

Я бы также избежал блокировки мьютекса на время использования std::cout,cout обычно достаточно медленный, что может привести к конфликту из-за блокировки.Обычно лучше (только для одного примера) отформатировать данные в буфере, поместить буфер в очередь и иметь один поток, который считывает элементы из очереди и отправляет их в cout.Таким образом, вам нужно будет блокировать только достаточно долго, чтобы добавить / удалить буфер в / из очереди.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...