Разрешено ли компилятору переупорядочивать операторы вокруг `std::condition_variable::notify_one`?
Следующий код представляет собой структуру, которую я написал, чтобы позволить мне ставить работу в очередь для выполнения в нескольких рабочих потоках, и которая блокирует основной поток до тех пор, пока не станет доступен новый рабочий поток.
struct WorkQueue{
const std::size_t size;
std::vector<uint8_t> threadActive;
std::condition_variable cond;
std::mutex mu;
std::vector<std::jthread> threads;
WorkQueue(std::size_t size_ = 1) :
size{size_}
{
threads.resize(size);
threadActive.resize(size);
std::fill(std::begin(threadActive), std::end(threadActive), false);
}
template<typename Function>
void enqueue(Function&& f){
auto numActiveThreads = [&](){
return std::count(std::begin(threadActive), std::end(threadActive), true);
};
auto availableThread = [&](){
return std::find(std::begin(threadActive), std::end(threadActive), false) - std::begin(threadActive);
};
std::unique_lock<std::mutex> lock{mu};
//wait until a thread becomes available
if(numActiveThreads() == size){
cond.wait(lock, [&](){ return numActiveThreads() != size; });
}
//get an available thread and mark it as active
auto index = availableThread();
threadActive[index] = true;
//start the new thread and swap it into place
std::jthread thread{[this, index, fn = std::forward<Function>(f)](){
fn();
threadActive[index] = false;
cond.notify_one();
}};
threads[index].swap(thread);
}
};
У меня есть два вопроса о коде лямбда-выражения, выполняемом
jthread
:
Нужно ли блокировать мьютекс
mu
при настройке?Разрешено ли компилятору переупорядочивать код и выполнять
cond.notify_one()
перед установкойthreadActive[index] = false
?
Я думаю, что необходимо заблокировать мьютекс тогда и только тогда, когда компилятору разрешено изменять порядок операторов. Это правильно?