attempting:
To do a delayed start on multiple threads.
problem:
I've created the example below to prove out the idea and attempted to create a race codition on x to prove out that all the threads would run concurrently.
It seems like things are serialize instead of running in parallel-the desired behavior, but maybe each thread runs for too short a period and finishes before the other onse get serviced
Sometimes a thread will get stuck on the cv.wait --- I've viewed this in GDB and can see one of the threads just sitting on the wait in frame 0 --- meaning the notify_all did not wak ALL the threads --- (this is sporadic behavior and happens every few attempts at running the binary)
asking:
Is using the condition variable a valid method for performing a delayed startup of a group of threads with the desired behavior that they will all run in parallel?
Why is the notify_all() not waking ALL the threads?
code:
// main.cpp
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>
#include <iostream>
#include <unistd.h>
int main()
{
std::condition_variable cv;
std::mutex cv_m;
int x = 0;
std::thread t1 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t1 x:" << x++ << std::endl;});
std::thread t2 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t2 x:" << x++ << std::endl;});
std::thread t3 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t3 x:" << x++ << std::endl;});
std::thread t4 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t4 x:" << x++ << std::endl;});
std::thread t5 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t5 x:" << x++ << std::endl;});
std::cout << "STARTING" << std::endl;
cv.notify_all();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
std::cout << "DONE" << std::endl;
return 0;
}
compiling:
g++ -std=c++14 main.cpp -lpthread
running:
./a.out
Condition variables are stateless. Notifications get lost if there are no waiters; spurios notifications can be delivered. You need to wait for a change of a shared state, rather than a signal from a condition variable.
std::condition_variable:
When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, the thread is awakened, and the mutex is atomically reacquired. The thread should then check the condition and resume waiting if the wake up was spurious.
Also, when notifying a condition variable the mutex must be held if waiter FIFO order needs to be preserved.
Fixes:
int main()
{
std::condition_variable cv;
std::mutex cv_m;
int x = 0;
bool start = false;
auto thread_fn = [&]{
std::unique_lock<std::mutex> lk(cv_m);
while(!start)
cv.wait(lk);
std::cout << "t1 x:" << x++ << std::endl;
};
std::thread t1 = std::thread(thread_fn);
std::thread t2 = std::thread(thread_fn);
std::thread t3 = std::thread(thread_fn);
std::thread t4 = std::thread(thread_fn);
std::thread t5 = std::thread(thread_fn);
std::cout << "STARTING" << std::endl;
{
std::unique_lock<std::mutex> lock(cv_m);
start = true;
cv.notify_all();
}
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
std::cout << "DONE" << std::endl;
}
Related
In my application, many threads notify a waiting thread. Sometimes these notifications are very close to each other in time and the waiting thread misses the notification. Is there any easy way to counter this issue? A small example code is given below. In the code, the task2 notifies the waiting thread but the waiting thread, waitingForWork, miss the notification.
#include <condition_variable>
#include <iostream>
#include <thread>
std::mutex mutex_;
std::condition_variable condVar;
bool dataReady{ false };
void waitingForWork() {
for (int i = 0; i < 2; i++)
{
std::cout << "Waiting " << std::endl;
std::unique_lock<std::mutex> lck(mutex_);
condVar.wait(lck, [] { return dataReady; });
dataReady = false;
std::cout << "Running " << std::endl;
}
}
void task1() {
std::this_thread::sleep_for(std::chrono::milliseconds{ 45 });
std::lock_guard<std::mutex> lck(mutex_);
dataReady = true;
std::cout << "Task1 Done:" << std::endl;
condVar.notify_one();
}
void task2() {
std::this_thread::sleep_for(std::chrono::milliseconds{ 46 });
std::lock_guard<std::mutex> lck(mutex_);
dataReady = true;
std::cout << "Task2 Done" << std::endl;
condVar.notify_one();
}
int main() {
std::cout << std::endl;
std::thread t1(waitingForWork);
std::thread t2(task1);
std::thread t3(task2);
t1.join();
t2.join();
t3.join();
std::cout << std::endl;
system("pause");
}
It's a multiple producer single consumer problem. Which is described here:
Multiple consumer single producer problem
So basically you have to change your code in a way that each thread have to write notifications into a threadsafe queue.
And then your worker thread has to work on this queue and will not miss anymore notifications.
attempting:
To do a delayed start on multiple threads.
problem:
I've created the example below to prove out the idea and attempted to create a race codition on x to prove out that all the threads would run concurrently.
It seems like things are serialize instead of running in parallel-the desired behavior, but maybe each thread runs for too short a period and finishes before the other onse get serviced
Sometimes a thread will get stuck on the cv.wait --- I've viewed this in GDB and can see one of the threads just sitting on the wait in frame 0 --- meaning the notify_all did not wak ALL the threads --- (this is sporadic behavior and happens every few attempts at running the binary)
asking:
Is using the condition variable a valid method for performing a delayed startup of a group of threads with the desired behavior that they will all run in parallel?
Why is the notify_all() not waking ALL the threads?
code:
// main.cpp
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>
#include <iostream>
#include <unistd.h>
int main()
{
std::condition_variable cv;
std::mutex cv_m;
int x = 0;
std::thread t1 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t1 x:" << x++ << std::endl;});
std::thread t2 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t2 x:" << x++ << std::endl;});
std::thread t3 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t3 x:" << x++ << std::endl;});
std::thread t4 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t4 x:" << x++ << std::endl;});
std::thread t5 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t5 x:" << x++ << std::endl;});
std::cout << "STARTING" << std::endl;
cv.notify_all();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
std::cout << "DONE" << std::endl;
return 0;
}
compiling:
g++ -std=c++14 main.cpp -lpthread
running:
./a.out
Condition variables are stateless. Notifications get lost if there are no waiters; spurios notifications can be delivered. You need to wait for a change of a shared state, rather than a signal from a condition variable.
std::condition_variable:
When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, the thread is awakened, and the mutex is atomically reacquired. The thread should then check the condition and resume waiting if the wake up was spurious.
Also, when notifying a condition variable the mutex must be held if waiter FIFO order needs to be preserved.
Fixes:
int main()
{
std::condition_variable cv;
std::mutex cv_m;
int x = 0;
bool start = false;
auto thread_fn = [&]{
std::unique_lock<std::mutex> lk(cv_m);
while(!start)
cv.wait(lk);
std::cout << "t1 x:" << x++ << std::endl;
};
std::thread t1 = std::thread(thread_fn);
std::thread t2 = std::thread(thread_fn);
std::thread t3 = std::thread(thread_fn);
std::thread t4 = std::thread(thread_fn);
std::thread t5 = std::thread(thread_fn);
std::cout << "STARTING" << std::endl;
{
std::unique_lock<std::mutex> lock(cv_m);
start = true;
cv.notify_all();
}
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
std::cout << "DONE" << std::endl;
}
According to several documentation examples the thread can't unlock a mutex unless it locked it explicitly. Here is an excerpt from man page for pthread_mutex_unlock at IBM.
The pthread_mutex_unlock() function unlocks the mutex specified. If
the calling thread does not currently hold the mutex (via a previous
call to pthread_mutex_lock(), pthread_mutex_trylock(), or
pthread_mutex_timedlock_np()) the unlock request fails with the EPERM
error.
Even the new C++ standard says something similar about the thread ownership, yet the following program was able to unlock a mutex locked on a different thread. On gcc & Linux systems the same behavior is seen both on pthread mutex as well as std::mutex (which I believe is implemented based on pthread_mutex anyway).
#include <iostream>
#include <thread>
#include <mutex>
#include <pthread.h>
std::mutex stmutex;
pthread_mutex_t pthrmutex = PTHREAD_MUTEX_INITIALIZER;
void thread1(int i)
{
stmutex.unlock();
std::cout << "Un Locked in thread 1" << std::this_thread::get_id() << std::endl;
}
void pthread1(int i)
{
pthread_mutex_unlock(&pthrmutex);
std::cout << "Un Locked Pthread mutex in thread 1" << std::this_thread::get_id() << std::endl;
}
void thread2(int i)
{
stmutex.lock();
std::cout << "Locked in thread 2" << std::this_thread::get_id() << std::endl;
}
void thread3(int i)
{
stmutex.unlock();
std::cout << "UNLocked in thread 3" << std::this_thread::get_id() << std::endl;
}
int main(int argc, char **argv)
{
try {
stmutex.lock();
std::cout << "Locked in main thread : " << std::this_thread::get_id() << std::endl;
std::thread t1(thread1,1);
t1.join();
stmutex.lock();
std::cout << "Locked in main thread after unlocking in thread1" << std::endl;
stmutex.unlock();
std::cout << "Un Locked in main thread " << std::endl;
pthread_mutex_lock(&pthrmutex);
std::cout << "Locked pthread mutex in main thread : " << std::this_thread::get_id() << std::endl;
std::thread t2(pthread1,1);
t2.join();
pthread_mutex_lock(&pthrmutex);
std::cout << "Locked Pthread mutext in main thread after unlocking in thread1" << std::endl;
pthread_mutex_unlock(&pthrmutex);
std::cout << "Un Locked Pthread mutext in main thread " << std::endl;
std::thread t3(thread2,1);
t3.join();
std::thread t4(thread3,1);
t4.join();
} catch (std::exception& ex)
{
std::cerr << "Exception In main thread: " << ex.what() << std::endl;
}
}
Am I missing anything in my understanding of mutex "Ownership" ?
The request fails with the EPERM error only for mutexes created with PTHREAD_MUTEX_ERRORCHECK.
See pthread_mutex_lock section RATIONALE:
... while being able to extract the thread ID of the owner of a mutex might be desirable, it would require storing the current thread ID when each mutex is locked, and this could incur unacceptable levels of overhead.
I.e. initialize your mutex with PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP.
Example:
void locker(pthread_mutex_t* mutex) {
if(int e = pthread_mutex_lock(mutex))
fprintf(stderr, "pthread_mutex_lock: (%d)%s\n", e, strerror(e));
}
void unlocker(pthread_mutex_t* mutex) {
if(int e = pthread_mutex_unlock(mutex))
fprintf(stderr, "pthread_mutex_unlock: (%d)%s\n", e, strerror(e));
}
int main() {
pthread_mutex_t a = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t b = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
std::thread(locker, &a).join();
std::thread(locker, &b).join();
std::thread(unlocker, &a).join();
std::thread(unlocker, &b).join(); // pthread_mutex_unlock: (1)Operation not permitted
}
I have been trying condition_variable::wait and precisely I am using :
template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate pred );
but I am a little bit confused when I executed it. This the simple example:
std::condition_variable cv;
std::mutex cv_m;
bool flag = false;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cerr << "Waiting... \n";
cv.wait(lk,[]() {return flag == true;});
std::cerr << "...finished waiting " << flag << std::endl;
}
void signals()
{
//std::this_thread::sleep_for(std::chrono::seconds(1));
std::unique_lock<std::mutex> lk(cv_m);
std::cout <<"Counting...."<< std::endl;
flag = true;
for(int i = 0; i < 5; i++) {
std::cout << i << std::endl;
}
cv.notify_all();
}
int main()
{
std::thread t1(waits), t2(waits), t3(waits), t4(signals);
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}
if I am delay the signals() with
std::this_thread::sleep_for(std::chrono::seconds(1));
it works as expected while if I put the above line under comment the output it is a mess.
Shouldnd the wait condition put on hold the execution of waits() anyway ? Why do I need a delay the output changes every time and most of the time messed up ?
An example of the output
Waiting...
Counting....
0
1
2
3
4
Waiting...
...finished waiting 1
Waiting...
...finished waiting 1
...finished waiting 1
Thank you for any help
You have a race condition. It is possible for t4 to grab the mutex and run to completion before the other threads have a chance to get into the wait. Thus they miss the signal.
You need to synchronize so that the t1, t2, and t3 get into the wait before t4 starts. Anytime a sleep seems to fix a problem in threaded code, you probably have a race condition that requires real synchronization to fix properly.
I don't see synchronized output when i comment the the line wait(1) in thread(). can I make them run at the same time (one after another) without having to use 'wait(1)'?
#include <boost/thread.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
boost::mutex mutex;
void thread()
{
for (int i = 0; i < 100; ++i)
{
wait(1);
mutex.lock();
std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
mutex.unlock();
}
}
int main()
{
boost::thread t1(thread);
boost::thread t2(thread);
t1.join();
t2.join();
}
"at the same time (one after another)" is contradictory. With a call to sleep() they run at the same time. Without a call to sleep(), they run one after another. With only 100 lines to output, thread t1 completes before t2 has a change to begin execution. On my computer, I had to set your loop counter to 10000 before t1 ran long enough for t2 to launch while t1 was still executing:
Thread 0x2305010: 0
Thread 0x2305010: 1
Thread 0x2305010: 2
...
Thread 0x2305010: 8730
Thread 0x2305010: 8731
Thread 0x23052a0: 0
Thread 0x23052a0: 1
...
Thread 0x23052a0: 146
Thread 0x23052a0: 147
Thread 0x2305010: 8732
Thread 0x2305010: 8733
etc
Oh, and yes, if your goal was to make the two threads take turns executing, boost::condition_variable is the solution:
boost::mutex mutex;
boost::condition_variable cv;
void thread()
{
for (int i = 0; i < 100; ++i)
{
boost::unique_lock<boost::mutex> lock(mutex);
std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
cv.notify_one();
cv.wait(lock);
}
cv.notify_one();
}