Concurrency with pthreads, a typical misbehaviour - c

I'm not sure whats wrong with the program below, but it doesn't print each and every language once, but randomly some more often, some more less and some wont print
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
char *messages[] = {
"English: Hello World!",
"French: Bonjour, le monde!",
"Spanish: Hola al mundo",
"Klingon: Nuq neH!",
"German: Guten Tag, Welt!",
"Russian: Zdravstvytye, mir!",
"Japan: Sekai e konnichiwa!",
"Latin: Orbis, te saluto!"
};
#define NUM_MESSAGES (sizeof( messages ) / sizeof( char* ))
void *PrintHello( void *messageid )
{
pthread_t taskid;
int *id_ptr, message_num;
taskid = pthread_self();
printf( "This is thread with ID %lu.\n", taskid );
message_num = *((int *) messageid);
printf( "%s \n", messages[message_num] );
pthread_exit( NULL );
}
int main( int argc, char *argv[] )
{
pthread_t threads[NUM_MESSAGES];
int rc, i;
for( i = 0; i < NUM_MESSAGES; i++ ) {
void * argument = (void*) &i;
rc = pthread_create( &threads[i], NULL, PrintHello, argument );
if( rc ) {
printf( "ERROR; return code from pthread_create() is %d\n", rc );
exit( -1 );
}
}
for( i = 0; i < NUM_MESSAGES; i++ ) {
pthread_join( threads[i], NULL );
}
pthread_exit( NULL );
}
I guess the problem is somehow connected with the argument pointer. I tried to lock different parts but with no success.

You're passing the address of the variable i, which the main thread keeps changing. So you're at the mercy of scheduling: will anyone change i before your thread has a chance to run ?
Instead, you could try directly passing the string, greatly simplifying the code:
rc = pthread_create( &threads[i], NULL, PrintHello, messages[i]);
void *PrintHello(void *arg)
{
char *msg = arg;
printf("%s\n", msg);
return NULL;
}
There's another, poorer alternative where you pass the actual value of i as the argument (not its address).

This is a typical race condition.
To be exact, after a new thread is created, the executing order of the threads determines the program outcome. There are two situations:
When the thread function PrintHello is executed before the next increments i++ and the assignment void * argument = (void*) &i; in main thread, it outputs what you expect.
When the new thread PrintHello has been created but does not get scheduled until the next i++ executed in main thread. In this situation, your reference of argument in the thread function, namely message_num = *((int *) messageid); is not what you expect.
A solution for this is to dynamically allocate (using malloc)argument, and free them in the thread function after using it.

One way to pass scalar integer arguments to thread functions is to (ab-)use the following text from ยง6.3.2.3 of the C99 standard:
(5) An integer may be converted to any pointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation.
Except for the last part of the second sentence, the following code should work on most systems:
int int_val;
...
pthread_create(..., ..., thread_func, (void *)int_val);
and then in thread_func cast it back to integer:
void *thread_func (void *data)
{
int int_arg = (int)data;
...
}

Related

Why are my threads I created not printed in order?

I have this program:
void *func(void *arg) {
pthread_mutex_lock(&mutex);
int *id = (int *)arg;
printf("My ID is %d\n" , *id);
pthread_mutex_unlock(&mutex);
}
int main() {
int i;
pthread_t tid[3];
// Let us create three threads
for (i = 0; i < 3; i++) {
pthread_create(&tid[i], NULL, func, (void *)&i);
}
for (i = 0; i < 3; i++) {
pthread_join(tid[i], NULL);
}
pthread_exit(NULL);
return 0;
}
I expected it to output this:
My ID is 0
My ID is 1
My ID is 2
But instead I get random output, such as this:
My ID is 0
My ID is 0
My ID is 2
Since I already added mutex lock, I thought it would solve the problem. What else did I do wrong? Is this related to race condition?
Here id points to the same variable i in main for all the threads.
int *id = (int *)arg;
printf("My ID is %d\n" , *id);
But the variable i is constantly being update by the two for-loops in main behind the threads back. So before the thread reaches the point of printf, the value of i, and therefore also the value of *id, may have changed.
There are a few ways to solve this. The best way depends on the use case:
Wait in main until the thread signals that it has made a copy of *id before modifying i or letting it go out of scope.
Declare and initialize an array, int thread_id[], and create the threads like this:
pthread_create(&tid[i], NULL, func, &thread_id[i]);
malloc some memory and and initialize it with a copy of i:
int *thread_id = malloc(sizeof(*thread_id));
*thread_id = i
pthread_create(&tid[i], NULL, func, thread_id);
Just don't forget to free your memory int the thread when you are finished using it. Or in main if the thread fails to start.
If i fits in a void * can pass its content directly as a parameter to the thread. To make sure it fits, you can declare it as intptr_t rather than int
(We basicly abuse the fact that pointers are nothing more than magic integers) :
void *func(void *arg) {
pthread_mutex_lock(&mutex);
// Here we interpret a pointer value as an integer value
intptr_t id = (intptr_t )arg;
printf("My ID is %d\n" , (int)id);
pthread_mutex_unlock(&mutex);
}
int main() {
intptr_t i;
pthread_t tid[3];
// Let us create three threads
for (i = 0; i < 3; i++) {
// Here we squeeze the integer value of `i` into something that is
// supposed to hold a pointer
pthread_create(&tid[i], NULL, func, (void *)i);
}
for (i = 0; i < 3; i++) {
pthread_join(tid[i], NULL);
}
// This does not belong here !!
// pthread_exit(NULL);
return 0;
}
Nope, no race conditions involved. (my b) There can be a race condition on i because all threads access it. Each thread gets started with a pointer to i. However, the main problem is that there is no guarantee that the thread will start and run the critical section while i holds the value you expect, in an order that you expect.
I'm assuming you declared the variable mutex globally and called pthread_mutex_init() somewhere to initialize it.
Mutexes are great to allow only one thread to access a critical section of code at a time. So the code as you've written creates all three threads to run in parallel, but only lets one thread at a time run the following code.
int *id = (int *)arg;
printf("My ID is %d\n" , *id);

Scope of 4th argument for pthread_create function in C threading

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// Let us create a global variable to change it in threads
int g = 0;
// The function to be executed by all threads
void *myThreadFun(void *vargp)
{
// Store the value argument passed to this thread
int *myid = (int *)vargp;
// Let us create a static variable to observe its changes
static int s = 0;
// Change static and global variables
++s; ++g;
// Print the argument, static and global variables
printf("Thread ID: %d, Static: %d, Global: %d\n", *myid, ++s, ++g);
}
int main()
{
int i;
pthread_t tid;
// Let us create three threads
for (i = 0; i < 3; i++)
pthread_create(&tid, NULL, myThreadFun, (void *)&i);
pthread_exit(NULL);
return 0;
}
I was just playing with aforementioned example in multithreading in C, and I got the same thread id for 2 threads and it shouldn't be because myid is a local pointer and should print different with each one.
I got the output as following:
Thread ID: 3, Static: 2, Global: 2
Thread ID: 3, Static: 4, Global: 4
Thread ID: 3, Static: 6, Global: 6
Can someone please explain me in brief?
You pass the very same pointer to all three threads. All threads will dereference the same pointer, getting the same value.
And because you call pthread_exit, the data the pointer is pointing to will not be alive anymore. And that means the dereference will lead to undefined behavior.
Furthermore since you access and modify shared data without synchronization you have data-races leading yet again to undefined behavior.
The first two problems can be easily solved by passing the value of i instead of a pointer to it. This is one of the very few cases where most people think it's okay to pretend that an integer is a pointer. You have to do some casting to make it work though:
pthread_create(&tid, NULL, myThreadFun, (void *) (intptr_t) i);
Then you have to do the opposite casting when getting the value:
int myid = (int) (intptr_t) vargp;
I got the same thread id for 2 threads and it shouldn't be because myid is a local pointer and should print different with each one.
myid is a local pointer, but it's actually pointing at an address from another thread. myid in all 3 threads you created pointed to the same address of i in main. So when you dereference myid, all threads read from the same location.
There are few issues.
Since main calls, pthread_exit, once the main thread exits and you can no longer access i from other threads. This is undefined behaviour.
All the threads actually read i (through myid). This is a data race - more than one thread accessing i without any
synchronisation.
Note that scope of an object doesn't determine the lifetime of an object. They are related but not the same.
the following proposed code:
cleanly compiles
performs the desired functionality
corrects the problems found in the OPs posted code
checks for (most) error conditions
uses a proper signature for the main() function
And now the proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define NUM_THREADS 3
// Let us create a global variable to change it in threads
int g = 0;
pthread_mutex_t myMutex;
// The function to be executed by all threads
void *myThreadFun( void *vargp )
{
// Store the value argument passed to this thread
int myid = (int) (intptr_t) vargp;
// Let us create a static variable to observe its changes
static int s = 0;
pthread_mutex_lock( &myMutex );
// Change static and global variables
++s;
++g;
// Print the argument, static and global variables
printf("Thread ID: %d, Static: %d, Global: %d\n", myid, s, g);
pthread_mutex_unlock( &myMutex );
pthread_exit( NULL );
}
int main( void )
{
pthread_t tid[ NUM_THREADS ] = {0};
if (pthread_mutex_init(&myMutex, NULL) != 0)
{
perror( "pthread_mutex_init failed" );
exit( EXIT_FAILURE );
}
// implied else, init successful
// Let us create three threads
for ( int i = 0; i < NUM_THREADS; i++)
{
if(pthread_create(&tid[i], NULL, myThreadFun, (void *) (intptr_t) i) != 0 )
{
perror( "pthread_create failed" );
exit( EXIT_FAILURE );
}
}
// collect the threads
for( int i=0; i< NUM_THREADS; i++ )
{
if( pthread_join( tid[i], NULL ) != 0 )
{
perror( "pthread_join failed" );
}
}
pthread_mutex_destroy( &myMutex );
return 0;
}
A typical run of the program results in the following output:
Thread ID: 0, Static: 1, Global: 1
Thread ID: 2, Static: 2, Global: 2
Thread ID: 1, Static: 3, Global: 3
Note: the field claiming to be the thread ID is only the order that the threads were created, not the actual thread id.

Creating threads and providing argument to the function in C

I am currently creating threads and I would like to print out the "thread number" of each thread I make. For example:
void* thread_function(void* arg){
printf("This is thread # %d\n", *(int*)arg);
return NULL;
}
pthread_t id;
int main()
for(int i = 0; i< 5; i++){
pthread_create(&id, NULL, thread_function, &i);
}
//do some other stuff
return 0;
}
So basically, for the first thread, I want it to say:
This is thread # 0
However, for some reason it gives me random numbers like
This is thread # -56465645645
How do I fix this problem?
You pased pointer to i that will vanish after exiting the for loop instead of value of i.
Try using (void*)i instead of &i in function main() and
passing (int)arg instead of *(int*)arg in function thread_function().
(conversion between pointers and intergers is implementation-defined)

return argument (struct) from a thread

I have a function task1 that is called by the pthread_create in the main (pure C). It works but, whatever I do on my_pair is lost after the thread is over. I mean I would like the created thread task1 do operations and save them on eventT.. is it possible to return my_pair? how?
void task1(void* eventT){
//struct eventStruct *my_pair = (struct eventStruct*)eventT;
// Tried with malloc but same wrong behavior
struct eventStruct *my_pair = malloc(sizeof((struct eventStruct*)eventT));
// do stuff
my_pair->text = TRIAL;
pthread_exit( my_pair );
}
// Global variable
struct eventStruct *eventT = NULL;
//Calling the thread from the main
eventT = (struct eventStruct*)
thpool_add_work(thpool, (void*)task1, (void*) &eventT);
// Expecting eventT changed (not happening..)
pthread_join( thread, &eventT );
Here's an example of one way to return a struct from a thread - by passing in an allocted struct for the thread to return. This example is similar to your posted code, but uses only pthread functions since I don't know anything about the thpool_add_work() API.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
struct eventStruct
{
char const* text;
char const* more_text;
};
#define TRIAL "this is a test"
void* task1(void* eventT)
{
struct eventStruct *my_pair = (struct eventStruct*)eventT;
// do stuff
my_pair->text = TRIAL;
pthread_exit( my_pair );
}
int main(void)
{
pthread_t thread;
struct eventStruct* thread_arg = malloc(sizeof *thread_arg);
thread_arg->text = "text initialized";
thread_arg->more_text = "more_text_initialized";
//Calling the thread from the main
pthread_create( &thread, NULL, task1, thread_arg);
void* thread_result;
pthread_join( thread, &thread_result);
struct eventStruct* eventT = thread_result;
puts(eventT->text);
puts(eventT->more_text);
free(eventT);
return 0;
}
Another way this could be done is by having the returned structure allocated by the thread instead of by the caller and passing it in. I'm sure there are many other mechanisms that can be used, but this should get you started.

Print arguments inside thread

void * consumer_child(void *arguments){
Range rng = *((Range *) arguments);
//prinnting with the range to easily identify each thread
printf("consumer_child[%d-%d] started\n", rng.start, rng.end );
pthread_exit(0);
}
When I print it, it prints memory location, not the value. I need to print the value.
In main thread start and end values are set properly. I have checked them.
in main I have set the argument as following
Range *rng = malloc(sizeof(*rng));
rng->start = i * numbersPerChild;
rng->end = (numbersPerChild * (i + 1)) -1 ;
printf("Range for thread %d is %d to %d\n", i, rng->start, rng->end );
printf("test print %d\n",rng->start);
pthread_create(&tid[i], NULL, consumer_child, (void *)&rng );
Range is a struct
typedef struct
{
int start;
int end;
} Range;
You need to change:
pthread_create(&tid[i], NULL, consumer_child, (void *)&rng );
to:
pthread_create(&tid[i], NULL, consumer_child, rng);
since rng is already a pointer, and you want to pass that, not its address. You don't need to cast an object pointer to void * in C, unless you have a variadic function that expects one and you're trying to pass it a different kind of object pointer.

Resources