I am currently trying to create a very simple thread pool using std::thread
.
In order to maintain threads 'alive' after their given task is done, I associate a std::mutex
with each one of them.
The principle is somewhat like this:
// Thread loop
while (1)
{
m_oMutex->lock();
m_oMutex->unlock();
m_bAvailable = false;
m_oTask();
m_bAvailable = true;
}
// ThreadPool function which gives a task to a thread
void runTask(boost::function<void ()> oTask)
{
[...]
m_oThreads[i]->setTask(oTask);
m_oMutexes[i]->unlock(); // same mutex as thread's m_oMutex
m_oMutexes[i]->lock();
}
To find the i
, the ThreadPool
searches for a thread object with m_bAvailable
set to true
. It unlocks the corresponding mutex so the thread
can lock it and execute its task. The thread
unlocks it immediately so the ThreadPool
can lock it again so the thread
is halted once its task is done.
But the question is, will locks be made in the order the threads ask them? In other words, if a thread
does a lock on a mutex
, then the ThreadPool
unlocks it and locks it again, am I sure that the lock will be given to the thread
first? If not, is there a way to ensure it?
You can use a fair mutex to solve your task, i.e. a mutex that will guarantee the FIFO order of your operations.
As long as you hold them, you can release Mutexes in any order. It may be more "efficient" if work can be done somewhere else with only one of the Mutexes to have a specific order of release, but it's still deadlock-free. This changes if you re-acquire the Mutex of course, but you are not doing that.
Mutex lock will only be released by the thread who locked it. So this ensures that once a thread has locked a piece of code then no other thread can execute the same region until it is unlocked by the thread who locked it.
To solve your issue, you can use std::recursive_mutex , which can be locked/unlocked multiple times from the same thread. From cppreference: A calling thread owns a recursive_mutex for a period of time that starts when it successfully calls either lock or try_lock .
No, you cannot guarantee that your thread loop will ever acquire the lock with your example as is. Use a conditional variable to signal to the thread loop that it should awake and take the lock. See std::condition_variable::wait(...)
.
condition-variable
More on this topic in general can be found here http://en.wikipedia.org/wiki/Condition_variable. If you were using the pthread library, the equivalent call would be pthread_cond_wait
in your "Thread loop" and pthread_cond_signal
in your runTask function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With