Да, он должен возвращать true.
[thread.thread.member]
void join();
4 Эффекты : блокируется до завершения потока, представленного *this
.
5 Синхронизация : Завершение потока, представленного *this
, синхронизируется с ([intro.multithread]) соответствующим успешным join()
возвратом.
Итак, выполнение потока, представленного дескриптором, и связанные с ним побочные эффекты выполняются до того, как join
возвращается в контекст вызова.
Пример
Давайте посмотрим надве функции, которые отличаются только тем, когда они присоединяются к потоку:
int count_A() {
int counter = 0;
bool flag(true);
auto t = std::thread([&]{flag = false;});
while(flag) { // infinite loop - flag never synchronized
++counter;
}
t.join(); // joins thread after loop exits
return counter;
}
int count_B() {
int counter = 0;
bool flag(true);
auto t = std::thread([&]{flag = false;});
t.join(); // joins thread before loop, forcing synchronization
while(flag) {
++counter;
}
return counter;
}
При компиляции с g ++ версии 8.2 при оптимизации -O3
, вызов count_A
приводит к бесконечному циклу, потому что компилятор принимает flag
всегда верно.
С другой стороны, вызов count_B
просто вернет значение 0
.Поскольку значение flag
проверяется после thread.join()
, его значение повторно загружается, а флаг равен false
, поэтому цикл while не выполняется.
Обратите внимание, что если flag
изменить на atomic_bool
, то count_A
будет вести себя как счетчик до тех пор, пока для флага не будет установлено значение false, а функция не войти в бесконечный цикл (вместо возврата один раз flag
устанавливается в значение false дочерним потоком).