pthread_cond_signal() doesn't wake up awaiting thread - c++

I'm testing pthread_cond_wait() if it could be woke up by signal function:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t _mutex(PTHREAD_MUTEX_INITIALIZER);
pthread_cond_t _cond (PTHREAD_COND_INITIALIZER);
void* producer(void*) {
pthread_mutex_lock(&_mutex);
printf("producer wait() begins\n");
pthread_cond_wait(&_cond, &_mutex);// hang here
printf("producer wait() ends\n"); // not printed
return NULL;
}
void* consumer(void*) {
sleep(1);
printf("consumer wait for lock\n");
pthread_mutex_lock(&_mutex);
printf("consumer signals\n");
pthread_cond_signal(&_cond);
sleep(2);
return NULL;
}
int main() {
pthread_t ptid, ctid;
pthread_create(&ptid, NULL, producer, NULL);
pthread_create(&ctid, NULL, consumer, NULL);
pthread_join(ptid, NULL);
pthread_join(ctid, NULL);
return 0;
}
It prints:
producer wait() begins
consumer wait for lock
consumer signals
It hangs there and never print producer wait() end. So what's happening here, why pthread_cond_wait is blocked?

Related

Not able to exit the child process properly using condition variable after handling a SIGTERM

I have created a child process where I am handling a SIGTERM sent from the parent process. In the child process I am waiting on a condition_variable cv inside a new thread waitingForWork(). cv is set by the SIGTERM signal handler inside stopTheWait() function.
For some reason the stopTheWait() function cannot acquire the lock and waitingForWork() waits for ever and doTheCleanUp() is never called.
Finally the Parent process closes.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
void stopTheWait(){
printf("[CHILD] Stopping the wait.. \n\n");
std::lock_guard<std::mutex> lck(mtx);
cv.notify_all();
}
void signal_callback_handler(int signum)
{
printf("[CHILD] Caught signal, trying to stop the wait... %d\n\n",signum);
stopTheWait();
}
void doTheCleanUp()/* is never called*/ {
printf("[CHILD] clean up... \n\n");
}
void waitingForWork(){
printf("[CHILD] wait for ever... \n\n");
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck);
doTheCleanUp();
printf("[CHILD] clean Up Done, now end wait... \n\n");
exit(0);
}
int main()
{
printf("[PARENT] in parent...\n");
int pid;
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0)
{ /* child */
signal(SIGTERM, signal_callback_handler);
std::unique_lock<std::mutex> lck(mtx);
std::thread t1(waitingForWork);
t1.join();
waitingForWork();
printf("[CHILD] wait is over...\n\n");
}
else /* parent */
{ /* pid hold id of child */
sleep(3); /* pause for 3 secs */
printf("[PARENT] sending SIGTERM\n\n");
kill(pid, SIGTERM);
sleep(3);
}
printf("[PARENT] exiting parent...\n");
sleep(1);
return 0;
}
I see below print.
[support.signal]/3 An evaluation is signal-safe unless it includes one of the following:
(3.1) — a call to any standard library function, except for plain lock-free atomic operations and functions explicitly identified as signal-safe.
...
A signal handler invocation has undefined behavior if it includes an evaluation that is not signal-safe.
There's very little one can safely do in a signal handler. printf, mutex and condition variable operations are right out.

crashed when using multiple consumer thread

Only one consumer works fine, but multiple consumers will crash, I am wondering why.
#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
#include <unistd.h>
#include <queue>
using namespace std;
pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t g_qs_notempty = PTHREAD_COND_INITIALIZER;
pthread_cond_t g_qs_notfull = PTHREAD_COND_INITIALIZER;
queue<string> qs;
void *
producer(void *arg)
{
static vector<string> vs{"a ","b ","c ","d ","e "};
static int idx = 0;
while(1){
pthread_mutex_lock(&g_mutex);
if(qs.size()==5)//full
pthread_cond_wait(&g_qs_notfull,&g_mutex);
qs.push(vs[idx]);
idx = (idx+1)%5;
pthread_cond_signal(&g_qs_notempty);
pthread_mutex_unlock(&g_mutex);
}
return NULL;
}
void *
consumer(void *arg)
{
while(1){
pthread_mutex_lock(&g_mutex);
if(qs.empty())
pthread_cond_wait(&g_qs_notempty,&g_mutex);
cout<<qs.front();
qs.pop();
pthread_cond_signal(&g_qs_notfull);
pthread_mutex_unlock(&g_mutex);
}
return NULL;
}
int main()
{
struct thread_info *tinfo;
pthread_attr_t attr;
pthread_t thread_id;
pthread_attr_init(&attr);
pthread_create(&thread_id, &attr, &producer, 0);
pthread_create(&thread_id, &attr, &consumer, 0);
pthread_create(&thread_id, &attr, &consumer, 0); //adding this line will crash
pthread_exit(0);
}
It is not guaranteed that _signal() wakes up only a single thread.
So you must recheck your condition upon wakeup. A simply way to fix your code is to switch the if for while.

How to start a thread when an event occurs and close their handles crrectly

I'm making a service, which is listening on a logon event. If this event occurs, my application should start a new thread, which will do the work.
My question is, how can i start a new thread every time a logon event occurs, and close it's handle correctly if the thread is done working. My problem is, that i don't know how many logon event will occur, so i can't user WaitForMultipleObjects because it's first parameter is the number of threads it should wait for.
while ( WaitForSingleObject( ghSvcStopEvent, 0 ) != WAIT_OBJECT_0 )
{
DWORD dwEventFlags;
BOOL bRes;
// WTSWaitSystemEvent waits until a logon event ocurs
bRes = WTSWaitSystemEvent( WTS_CURRENT_SERVER_HANDLE, WTS_EVENT_LOGON, &dwEventFlags );
if ( dwEventFlags == WTS_EVENT_NONE )
{
ShowErrorText( "Cancelling waiting for logon event. Service shutting down.", 0, true );
}
if ( bRes )
{
// Someone has logged on
HANDLE hThread = CreateThread( NULL, 0, ServiceWorkerThread, NULL, 0, &dwThreadID );
}
else
{
ShowErrorText( "WTSWaitSystemEvent failed.", GetLastError(), true );
}
}//while
Could someone help me?
Thanks!
If you can use C++11 (starting VS2010), you an use condition variable that will do the job for you
The idea of a condition variable is:
one variable that allows threads to comunicate together.
if you notify it, you send a signal to other threads pluged on it
if you do cv.wait(...) on it, you wait for other threads to signal that sonething has happenend and then you test your condition again.
Here is an example
Server.h
#include <condition_variable>
#include <mutex>
class CServer
{
std::condition_variable & cv;
std::mutex & mut;
bool & flag;
public:
~CServer(void);
CServer::CServer(std::condition_variable & cv,
std::mutex & mut,
bool & flag);
CServer::CServer(CServer &);
int Notify();
int DisplayNotification();
std::condition_variable & getCondVar(){return cv;}
std::mutex & getMutex(){return mut;}
bool & getFlag(){return flag;}
};
Server.cpp
#include "Server.h"
#include <iostream>
using namespace std;
CServer::~CServer(void)
{
}
CServer::CServer(std::condition_variable & cv_,
std::mutex & mut_,
bool & flag_):
cv(cv_),
mut(mut_),
flag(flag_)
{
}
CServer::CServer(CServer &toCopy):
cv(toCopy.getCondVar()),
mut(toCopy.getMutex()),
flag(toCopy.getFlag())
{
flag=false;
cout<<"Copy constructor"<<std::endl;
}
int CServer::Notify()
{
{
std::lock_guard<std::mutex> lk(mut);
flag=true;
std::cout << "ready for notfication"<<endl;
}
cv.notify_one();
return 0;
}
int CServer::DisplayNotification()
{
// wait for the worker
{
std::unique_lock<std::mutex> lk(mut);
cv.wait(lk, [this]{return this->getFlag();});
}
cout<<"Notification displayed"<<endl;
return 0;
}
Client.h
#include <chrono>
#include "Server.h"
class CClient
{
CServer & serv;
std::chrono::seconds sleepTime;
bool finishedWork;
public:
CClient(CServer & serv,
std::chrono::seconds sleepTime);
~CClient(void);
int work();
};
Client.cpp
#include "Client.h"
#include <thread>
using namespace std;
CClient::CClient(CServer & serv_,
std::chrono::seconds sleepTime_):
serv(serv_),
sleepTime(sleepTime_),
finishedWork(false)
{
}
CClient::~CClient(void)
{
}
int CClient::work()
{
this_thread::sleep_for(sleepTime);
finishedWork=true;
serv.Notify();
return 0;
}
Main.cpp
#include "Client.h"
#include <thread>
using namespace std;
int main()
{
std::chrono::seconds sleepTime=std::chrono::seconds(10);
//create client and server
condition_variable cv;
mutex mut;
bool flag=false;
CServer serv(cv,mut, flag);
CClient cli(serv,sleepTime);
//thread with the server
thread thServ(&CServer::DisplayNotification,serv);
////thread with the client
thread thCli (&CClient::work,cli);
////join threads
thServ.join();
thCli.join();
return 0;
}
Ask me if you have any questions,
Hope that helps

producer & consumer - multithreading

I wrote a multithreading program like this,
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
using namespace std;
pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t ec = PTHREAD_COND_INITIALIZER;
pthread_cond_t fc = PTHREAD_COND_INITIALIZER;
queue<int> qu;
const int N = 2;
void *producer(void *arg)
{
while(1) {
pthread_mutex_lock(&mu);
int tmp = rand();
qu.push(tmp);
pthread_cond_signal(&ec);
if ((int) qu.size() > N) {
pthread_cond_wait(&fc, &mu);
}
pthread_mutex_unlock(&mu);
}
}
void *consumer(void *arg)
{
while(1) {
pthread_mutex_lock(&mu);
if ((int) qu.size() < 1) {
pthread_cond_wait(&ec, &mu);
}
int tmp = qu.front();
qu.pop();
if ((int) qu.size() <= N) {
pthread_cond_signal(&fc);
}
pthread_mutex_unlock(&mu);
//sleep(1);
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, NULL, producer, NULL);
for (int i = 0; i < N; i++) {
pthread_t tid;
pthread_create(&tid, NULL, consumer, NULL);
}
printf("all created\n");
sleep(600);
}
When the qu.size() is geater than N, producer should stop producing, and when it's less than N, producer resumes producing.
The weired problem is, if I remove the sleep(1); in consumer, the program will run into segmentation fault, if I keep sleep(1);, the program runs ok.
Why? Does it mean the consumer consumes too fast?
Spurious wakeup might be the reason. Your thread will proceed if the condition is true, but if your thread proceeds you can't assume the condition is true.
Spurious wakeups from the pthread_cond_timedwait() or pthread_cond_wait() functions may occur. Since the return from pthread_cond_timedwait() or pthread_cond_wait() does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.
So for example
if (qu.size() == 0) {
pthread_cond_wait(&ec, &mu);
}
should become
while (qu.size() == 0) {
pthread_cond_wait(&ec, &mu);
}
If you keep the sleep(1) call and the whole thing does not crash you're just lucky :)
Try initializing the mutex explicitly using the pthread_mutex_init() otherwise your pthread_mutex_lock() calls seem to fail.
From the docs:
Errors
The pthread_mutex_lock() and pthread_mutex_trylock()
functions may fail if:
EINVAL: The value specified by mutex
does not refer to an initialized mutex object.

Pthread locking

I have created MutexCondition class like this
/*MutexCondtion.h file*/
#ifndef MUTEXCONDITION_H_
#define MUTEXCONDITION_H_
#include <pthread.h>
#include <stdio.h>
class MutexCondition {
private:
bool init();
bool destroy();
protected:
pthread_mutex_t m_mut;
pthread_cond_t m_con;
public:
MutexCondition(){
init();
}
virtual ~MutexCondition(){
destroy();
}
bool lock();
bool unLock();
bool wait();
bool signal();
};
#endif /* MUTEXCONDITION_H_ */
MutexCondtion.cpp file
#include "MutexCondition.h"
bool MutexCondition::init(){
printf("MutexCondition::init called\n");
pthread_mutex_init(&m_mut, NULL);
pthread_cond_init(&m_con, NULL);
return true;
}
bool MutexCondition::destroy(){
pthread_mutex_destroy(&m_mut);
pthread_cond_destroy(&m_con);
return true;
}
bool MutexCondition::lock(){
pthread_mutex_lock(&m_mut);
return true;
}
bool MutexCondition::unLock(){
pthread_mutex_unlock(&m_mut);
return true;
}
bool MutexCondition::wait(){
pthread_cond_wait(&m_con, &m_mut);
return true;
}
bool MutexCondition::signal(){
pthread_cond_signal(&m_con);
return true;
}
And I created a WorkHandler which extends the MutexCondition
#ifndef WORKHANDLER_H_
#define WORKHANDLER_H_
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <pthread.h>
#include <stdio.h>
#include <list>
#include "MutexCondition.h"
#include "Work.h"
using namespace::std;
class WorkHandler: MutexCondition {
private:
int m_maxThreads;
queue<Work*> m_workQueue;
list<pthread_t*> m_workThreadList; //Just thread IDs
pthread_t **m_workThreads;
void workLoop();
bool initThreads();
void insertWork(Work *work);
Work* getWork();
protected:
static void* runWorkThread(void* delegate);
public:
WorkHandler(int maxThreads);
virtual ~WorkHandler();
};
#endif /* WORKHANDLER_H_ */
WorkHandler.cpp file
#include "WorkHandler.h"
WorkHandler::WorkHandler(int maxThreads) {
// TODO Auto-generated constructor stub
m_maxThreads = maxThreads;
initThreads();
}
WorkHandler::~WorkHandler() {
// TODO Auto-generated destructor stub
}
void* WorkHandler::runWorkThread(void *delegate){
printf("WorkHandler::runWorkThread called\n");
WorkHandler *ptr = reinterpret_cast<WorkHandler*>(delegate);
ptr->workLoop();
return NULL;
}
void WorkHandler::workLoop(){
printf("WorkHandler::workLoop called\n");
//WorkHandler *ptr = reinterpret_cast<WorkHandler*>(delegate);
while(1){
Work *work = getWork();
}
}
bool WorkHandler::initThreads(){
for(int i=0; i < m_maxThreads; i++){
pthread_t *thread(new pthread_t);
m_workThreadList.push_back(thread);
if(pthread_create(thread, NULL, runWorkThread, reinterpret_cast<void *>(this))!=0){
perror("InitThreads, pthread_create error \n");
return false;
}
pthread_detach(*thread);
}
return true;
}
void WorkHandler::insertWork(Work* w){
printf("WorkHandler::Thread %d insertWork locking\n", pthread_self());
lock();
printf("WorkHandler::insertWork Locked and inserting int queue \n");
m_workQueue.push(w);
signal();
unLock();
}
Work* WorkHandler::getWork(){
printf("WorkHandler::getWork locking\n");
lock();
printf("WorkHandler::getWork locked\n");
while(m_workQueue.empty()){//Need while instead of If
printf("WorkHandler::getWork waiting...\n");
wait();
}
Work *work = m_workQueue.front();
printf("WorkHandler::getWork got a job\n");
m_workQueue.pop();
unLock();
return work;
}
The problem is that I have locked the mutex variable in the getWork() function like this
printf("WorkHandler::getWork locking\n");
lock();
printf("WorkHandler::getWork locked\n");
However, if I see the log statements then all threads printed these two log statements and I think this is a problem. I am not putting anything into the queue so the first thread should wait the condition variable to be signaled and it works ok. But how come other thread can enter the area behind the lock although the first thread locked and has not called the unlock() function.
I was wondering if this is working correctly. Pleas let me know if you guys can see anything I need to fix. Thanks in advance.
The reason is that that when a thread waits on a condition variable the mutex is unlocked.
This is expected behavior.
When the condition variable is signaled the thread is not released to run until the lock is re-acquired.
If you change the function to this:
Work* WorkHandler::getWork(){
// Remoed this as it is non-determinstic when it will be printed.
lock();
printf("WorkHandler::getWork locked\n");
while(m_workQueue.empty()){//Need while instead of If
printf("WorkHandler::getWork waiting...\n");
wait();
printf("WorkHandler::getWork waiting DONE\n"); // Added this.
}
Work *work = m_workQueue.front();
printf("WorkHandler::getWork got a job\n");
m_workQueue.pop();
unLock();
return work;
}
If you then created three threads I would expect:
WorkHandler::getWork locked
WorkHandler::getWork waiting...
WorkHandler::getWork locked;
WorkHandler::getWork waiting...
WorkHandler::getWork locked
WorkHandler::getWork waiting...
For each call to signal I would expect:
WorkHandler::Thread %d insertWork locking
WorkHandler::insertWork Locked and inserting int queue
WorkHandler::getWork waiting DONE
WorkHandler::getWork got a job
No matter how fast you call signal I would always expect to see these two printed in order.
Because the thread is not released from the condition variable until it has re-acquired the lock.
Note you may see.
WorkHandler::Thread %d insertWork locking
WorkHandler::insertWork Locked and inserting int queue
WorkHandler::getWork locked // A previously released thread finishes and steals
// the job before the signalled thread can aquire the lock.
WorkHandler::getWork got a job
WorkHandler::getWork waiting DONE // Now the released thread just goes back to waiting.
WorkHandler::getWork waiting...