mardi 29 janvier 2019

Question on atomic spin lock and std::this_thread::yield()

I've been trying to implement C++ a thread pool with STL that takes in tasks in queues and dispatch the tasks to the threads for execution. The queue uses a atomic spin-lock when pushing and popping, and everything seemed to work well with the following code:

void push(const std::function<bool()>& func){
    while(in_use.exchange(true, std::memory_order_acquire));
    //Actually push the queue, deal with possible exceptions, etc.
    in_use.store(false, std::memory_order_release);
}

std::function<bool()> pop(){
    while(in_use.exchange(true, std::memory_order_acquire));
    //Actually push the queue, deal with possible exceptions, etc.
    in_use.store(false, std::memory_order_release);
}
.....//other functions for determining size, etc.

Later I decided that std::this_thread::yield may be a good choice in the loop.

(I tanked my PC when I was testing with a task that pushes the same task into the pool, and then polls the pool, when I set the process execution priority to Real-time...)

However, when I changed the line

while(in_use.exchange(true, std::memory_order_acquire));

to

while(in_use.exchange(true, std::memory_order_acquire)) std::this_thread::yield();

Under the same condition (task being pushing a same task to pool, with more tasks than threads in the pool.) with no other modification, all of the threads that pushes into the pool's master queue got blocked in deadlock, all waiting for variable to be released after running a few minutes.

I was wondering what exactly the yield function can do to a atomic variable operation that could lead to this problem.

PS: CPU hardware: Intel Core i5, OS Windows 10 1803, VS 2017 SDK version 10.0.17763.0.

Aucun commentaire:

Enregistrer un commentaire