pthread_cond_timedwait not returning after specified timeout - pthreads

In the following code execute_on_thread() will keep on printing ".",
while the main function waits for a condition to be signaled from execute_on_thread using pthread_cond_timedwait. However, it is not timing out after the specified 20 second timeout, it just keeps printing ".", nothing else is happening.
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define SHOW_TECH_CMD_MAX_EXEC_TIME 5 //in secs
pthread_mutex_t waitMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t waitCond = PTHREAD_COND_INITIALIZER;
void *execute_on_thread();
void *execute_on_thread()
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_mutex_lock( &waitMutex );
while(1)
{
printf(".");
}
pthread_cond_signal( &waitCond );
pthread_mutex_unlock( &waitMutex );
return (void *) 0;
}
int main( )
{
pthread_t tid;
struct timespec ts;
int error;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 20;
pthread_create(&tid,NULL,execute_on_thread,NULL);
pthread_mutex_lock(&waitMutex);
error = pthread_cond_timedwait(&waitCond, &waitMutex,&ts);
pthread_mutex_unlock(&waitMutex);
printf("come here 1\n");
if(error == ETIMEDOUT)
{
printf("come here 2\n");
error = pthread_cancel(tid);
if(error != 0)
{
printf("come here 3\n");
}
}
}

Have a look at the documentation for pthread_cond_wait:
Upon successful return, the mutex shall have been locked and shall be
owned by the calling thread.
So, before pthread_cond_wait returns, be it due to a signal arriving or timing out, it tries to lock the mutex. But - since execute_on_thread never releases the mutex once it has it (due to the while(1) loop), pthread_cond_wait will be stuck waiting on the mutex to be unlocked.
If you for instance change your execute_on_thread to temporarily unlock the mutex during each cycle, you should be able to get it to work. For instance:
void *execute_on_thread()
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); //Not necessary - this is the default state for new threads
pthread_mutex_lock( &waitMutex );
while(1)
{
printf(".\n");
pthread_mutex_unlock(&waitMutex);
usleep(100*1000); //So that the screen doesn't completely fill up with '.'s
pthread_mutex_lock( &waitMutex );
}
pthread_cond_signal( &waitCond );
pthread_mutex_unlock( &waitMutex );
return (void *) 0;
}
Note though, that there are a couple of other things that could be improved in your program - such as adding a guard variable to your conditional wait (have a look at condition variable - why calling pthread_cond_signal() before calling pthread_cond_wait() is a logical error?), adding a cleanup handler to make sure the mutex is unlocked if the cancel request is handled by execute_on_thread when the mutex is locked and similar tweaks.

Related

Should we use mutex with semaphore to make a correct synchronization and to prevent a race condition?

I am trying to see the race condition happens in the comsumer-producser problem,
so I made multiple producers and mulitple consumers.
From what I know that I need to provide mutex with semaphore:
Mutex for the race conditions, because muliple producers can access the buffer at the same time. then the data might be corrupted.
And semaphore to provide signaling between the producers and the consumers
The problem here that the sync is happening correctly while I am not using the Mutex (i am using the Semaphore only). is my understanding correct or is there anything wrong to do in the code below:
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>
int buffer;
int loops = 0;
sem_t empty;
sem_t full;
sem_t mutex; //Adding MUTEX
void put(int value) {
buffer = value;
}
int get() {
int b = buffer;
return b;
}
void *producer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
sem_wait(&empty);
//sem_wait(&mutex);
put(i);
//printf("Data Set from %s, Data=%d\n", (char*) arg, i);
//sem_post(&mutex);
sem_post(&full);
}
}
void *consumer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
sem_wait(&full);
//sem_wait(&mutex);
int b = get();
//printf("Data recieved from %s, %d\n", (char*) arg, b);
printf("%d\n", b);
//sem_post(&mutex);
sem_post(&empty);
}
}
int main(int argc, char *argv[])
{
if(argc < 2 ){
printf("Needs 2nd arg for loop count variable.\n");
return 1;
}
loops = atoi(argv[1]);
sem_init(&empty, 0, 1);
sem_init(&full, 0, 0);
sem_init(&mutex, 0, 1);
pthread_t pThreads[3];
pthread_t cThreads[3];
pthread_create(&cThreads[0], 0, consumer, (void*)"Consumer1");
pthread_create(&cThreads[1], 0, consumer, (void*)"Consumer2");
pthread_create(&cThreads[2], 0, consumer, (void*)"Consumer3");
//Passing the name of the thread as paramter, Ignore attr
pthread_create(&pThreads[0], 0, producer, (void*)"Producer1");
pthread_create(&pThreads[1], 0, producer, (void*)"Producer2");
pthread_create(&pThreads[2], 0, producer, (void*)"Producer3");
pthread_join(pThreads[0], NULL);
pthread_join(pThreads[1], NULL);
pthread_join(pThreads[2], NULL);
pthread_join(cThreads[0], NULL);
pthread_join(cThreads[1], NULL);
pthread_join(cThreads[2], NULL);
return 0;
}
I believe I have the problem figured out. Here's what is happening
When initializing your semaphores you set empty's number of threads to 1 and full's to 0
sem_init(&empty, 0, 1);
sem_init(&full, 0, 0);
sem_init(&mutex, 0, 1);
This means that there is only one "space" for the thread to get into the critical region. In other words, what your program is doing is
produce (empty is now 0, full has 1)
consume (full is now 0, empty has 0)
produce (empty is now 0, full has 1)
...
It's as if you had a token (or, if you like, a mutex), and you pass that token between consumers and producers. That is actually what the consumer-producer problem is all about, only that in most cases we are worried about having several consumers and producers working at the same time (which means you have more than one token). Here, because you have only one token, you basically have what one mutex would do.
Hope it helped :)

C Application with Pthread crashes

i have a problem with the pthread library in a C-Application for Linux.
In my Application a Thread is started over and over again.
But I allways wait until the Thread is finished before starting it.
At some point the thread doesn't start anymore and I get an out of memory error.
The solution I found is to do a pthread_join after the thread has finished.
Can anyone tell me why the Thread doesn't end correctly?
Here is an Example Code, that causes the same Problem.
If the pthread_join isn't called the Process stops at about 380 calls of the Thread:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>
volatile uint8_t check_p1 = 0;
uint32_t stack_start;
void *thread1(void *ch)
{
static int counter = 0;
int i;
int s[100000];
char stack_end;
srand(time(NULL) + counter);
for (i = 0; i < (sizeof (s)/sizeof(int)); i++) //do something
{
s[i] = rand();
}
counter++;
printf("Thread %i finished. Stacksize: %u\n", counter, ((uint32_t) (stack_start)-(uint32_t) (&stack_end)));
check_p1 = 1; // Mark Thread as finished
return 0;
}
int main(int argc, char *argv[])
{
pthread_t p1;
int counter = 0;
stack_start = (uint32_t)&counter; // save the Address of counter
while (1)
{
counter++;
check_p1 = 0;
printf("Start Thread %i\n", counter);
pthread_create(&p1, NULL, thread1, 0);
while (!check_p1) // wait until thread has finished
{
usleep(100);
}
usleep(1000); // wait a little bit to be really sure that the thread is finished
//pthread_join(p1,0); // crash without pthread_join
}
return 0;
}
The solution I found is to do a pthread_join after the thread has finished.
That is the correct solution. You must do that, or you leak thread resources.
Can anyone tell me why the Thread doesn't end correctly?
It does end correctly, but you must join it in order for the thread library to know: "yes, he is really done with this thread; no need to hold resources any longer".
This is exactly the same reason you must use wait (or waitpid, etc.) in this loop:
while (1) {
int status;
pid_t p = fork();
if (p == 0) exit(0); // child
// parent
wait(&status); // without this wait, you will run out of OS resources.
}

memory allocation of `getaddrinfo()`

I have a simple program which calls getaddrinfo() and freeaddrinfo().
I run valgrind on it, and it shows that there is no memory leak.
in use at exit: 0 bytes in 0 blocks
total heap usage: 108 allocs, 109 frees
However, I wrote a memory debugger named memleax which attaches the target process and traps at malloc() and free() to detect memory leak. I use memleax to detect the getaddrinfo() program, and it catches free() only 43 times.
Then I hook the malloc() and free() by malloc-hooks,
and it also shows free() only 43 times.
So my question is that, what is the difference between valgrind and hooking-malloc?
Original code:
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
int main()
{
struct addrinfo *aihead;
sleep(4);
printf(" --- getaddrinfo ---\n");
int error = getaddrinfo("dig.chouti.com", "http", NULL, &aihead);
if(error) {
printf("error: %s\n", gai_strerror(error));
return error;
}
sleep(4);
printf("\n\n\n --- freeaddrinfo ---\n");
freeaddrinfo(aihead);
sleep(4);
return 0;
}
Code with malloc-hook
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
/* Prototypes for __malloc_hook, __free_hook */
#include <malloc.h>
/* Prototypes for our hooks. */
static void my_init_hook (void);
static void *my_malloc_hook (size_t, const void *);
static void my_free_hook (void*, const void *);
static void *(*old_malloc_hook) (size_t, const void *);
static void (*old_free_hook) (void*, const void *);
static void
my_init (void)
{
old_malloc_hook = __malloc_hook;
old_free_hook = __free_hook;
__malloc_hook = my_malloc_hook;
__free_hook = my_free_hook;
}
static void *
my_malloc_hook (size_t size, const void *caller)
{
void *result;
/* Restore all old hooks */
__malloc_hook = old_malloc_hook;
__free_hook = old_free_hook;
/* Call recursively */
result = malloc (size);
/* Save underlying hooks */
old_malloc_hook = __malloc_hook;
old_free_hook = __free_hook;
/* printf might call malloc, so protect it too. */
printf ("malloc (%u) returns %p\n", (unsigned int) size, result);
/* Restore our own hooks */
__malloc_hook = my_malloc_hook;
__free_hook = my_free_hook;
return result;
}
static void
my_free_hook (void *ptr, const void *caller)
{
/* Restore all old hooks */
__malloc_hook = old_malloc_hook;
__free_hook = old_free_hook;
/* Call recursively */
free (ptr);
/* Save underlying hooks */
old_malloc_hook = __malloc_hook;
old_free_hook = __free_hook;
/* printf might call free, so protect it too. */
printf ("freed pointer %p\n", ptr);
/* Restore our own hooks */
__malloc_hook = my_malloc_hook;
__free_hook = my_free_hook;
}
int main()
{
my_init();
struct addrinfo *aihead;
printf(" --- getaddrinfo ---\n");
int error = getaddrinfo("dig.chouti.com", "http", NULL, &aihead);
if(error) {
printf("error: %s\n", gai_strerror(error));
return error;
}
sleep(4);
printf("\n\n\n --- freeaddrinfo ---\n");
freeaddrinfo(aihead);
sleep(4);
return 0;
}
I find this in valgrind's output:
--13197-- Discarding syms at 0x55f9240-0x5600454 in /usr/lib64/libnss_files-2.17.so due to mu
--13197-- Discarding syms at 0x580b100-0x580e590 in /usr/lib64/libnss_dns-2.17.so due to munm
--13197-- Discarding syms at 0x5a13a40-0x5a22854 in /usr/lib64/libresolv-2.17.so due to munma
==13197== Invalid free() / delete / delete[] / realloc()
==13197== at 0x4C2AD17: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==13197== by 0x4F9963B: __libc_freeres (in /usr/lib64/libc-2.17.so)
==13197== by 0x4A246B4: _vgnU_freeres (in /usr/lib64/valgrind/vgpreload_core-amd64-linux.s
==13197== by 0x4E6DE2A: __run_exit_handlers (in /usr/lib64/libc-2.17.so)
==13197== by 0x4E6DEB4: exit (in /usr/lib64/libc-2.17.so)
==13197== by 0x4E56B1B: (below main) (in /usr/lib64/libc-2.17.so)
==13197== Address 0x51f03d0 is 0 bytes inside data symbol "noai6ai_cached"
It seems that libc-nss frees some memory at __run_exit_handlers() after exit().
So maybe valgrid keeps tracing memory after target process's exit(). While malloc-hook stops working after exit().

Whats the difference between pthread_join and pthread_mutex_lock?

The following code is taken from this site and it shows how to use mutexes. It implements both pthread_join and pthread_mutex_lock:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *functionC();
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int counter = 0;
main()
{
int rc1, rc2;
pthread_t thread1, thread2;
/* Create independent threads each of which will execute functionC */
if( (rc1=pthread_create( &thread1, NULL, &functionC, NULL)) )
{
printf("Thread creation failed: %d\n", rc1);
}
if( (rc2=pthread_create( &thread2, NULL, &functionC, NULL)) )
{
printf("Thread creation failed: %d\n", rc2);
}
/* Wait till threads are complete before main continues. Unless we */
/* wait we run the risk of executing an exit which will terminate */
/* the process and all threads before the threads have completed. */
pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
exit(EXIT_SUCCESS);
}
void *functionC()
{
pthread_mutex_lock( &mutex1 );
counter++;
printf("Counter value: %d\n",counter);
pthread_mutex_unlock( &mutex1 );
}
I ran the code as given above as it is and it produced following result:
Counter value: 1
Counter value: 2
But in the second run i removed "pthread_mutex_lock( &mutex1 );" and "pthread_mutex_unlock( &mutex1 );" . I compiled and ran the code, it again produced the same result.
Now the thing that confuses me is why mutex lock is used in above code when same thing can be done without it (using pthread_join)? If pthread_join prevents another thread from running untill the first one has finished then i think it would already prevent the other thread from accessing the counter value. Whats the purpose of pthread_mutex_lock?
The join prevents the starting thread from running (and thus terminating the process) until thread1 and thread2 finish. It doesn't provide any synchronization between thread1 and thread2. The mutex prevents thread1 from reading the counter while thread2 is modifying it, or vice versa.
Without the mutex, the most obvious thing that could go wrong is that thread1 and thread2 run in perfect synch. They each read zero from the counter, each add one to it, and each output "Counter value: 1".

pthread_kill ends calling program

I am working on Ubuntu 12.04.2 LTS. I have a strange problem with pthread_kill(). The following program ends after writing only "Create thread 0!" to standard output. The program ends with exit status 138.
If I uncomment "usleep(1000);" everything executes properly. Why would this happen?
#include <nslib.h>
void *testthread(void *arg);
int main() {
pthread_t tid[10];
int i;
for(i = 0; i < 10; ++i) {
printf("Create thread %d!\n", i);
Pthread_create(&tid[i], testthread, NULL);
//usleep(1000);
Pthread_kill(tid[i], SIGUSR1);
printf("Joining thread %d!\n", i);
Pthread_join(tid[i]);
printf("Joined %d!", i);
}
return 0;
}
void sighandlertest(int sig) {
printf("print\n");
pthread_exit();
//return NULL;
}
void* testthread(void *arg) {
struct sigaction saction;
memset(&saction, 0, sizeof(struct sigaction));
saction.sa_handler = &sighandlertest;
if(sigaction(SIGUSR1, &saction, NULL) != 0 ) {
fprintf(stderr, "Sigaction failed!\n");
}
printf("Starting while...\n");
while(true) {
}
return 0;
}
If the main thread does not sleep a bit before raising the SIGUSR1, the signal handler for the thread created most propably had not been set up, so the default action for receiving the signal applies, which is ending the process.
Using sleep()s to synchronise threads is not recommended as not guaranteed to be reliable. Use other mechanics here. A condition/mutex pair would be suitable.
Declare a global state variable int signalhandlersetup = 0, protect access to it by a mutex, create the thread, make the main thread wait using pthread_cond_wait(), let the created thread set up the signal handle for SIGUSR1, set signalhandlersetup = 0 and then signal the condition the main thread is waiting on using pthread_signal_cond(). Finally let the main thread call pthread_kill() as by your posting.

Resources