The problem is in following:
I want to write a short program that creates 10 threads and each prints a tread "id" that is passed to thread function by pointer.
Full code of the program is below:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct params {
pthread_mutex_t mutex;
int id;
};
typedef struct params params_t;
void* hello(void* arg){
int id;
pthread_mutex_lock(&(*(params_t*)(arg)).mutex);
id = (*(params_t*)(arg)).id;
pthread_mutex_unlock(&(*(params_t*)(arg)).mutex);
printf("Hello from %d\n", id);
}
int main() {
pthread_t threads[10];
params_t params;
pthread_mutex_init (¶ms.mutex , NULL);
int i;
for(i = 0; i < 10; i++) {
params.id = i;
if(pthread_create(&threads[i], NULL, hello, ¶ms));
}
for(i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
The supposed output is (not necessary in this order):
Hello from 0
....
Hello from 9
Actual result is:
Hello from 2
Hello from 3
Hello from 3
Hello from 4
Hello from 5
Hello from 6
Hello from 8
Hello from 9
Hello from 9
Hello from 9
I tried to place mutex in different places in hello() function, but it didn't help.
How should I implement thread sync?
EDIT: Supposed result is not necessary 0...9 it can be any combination of these numbers, but each one should appear only one time.
The problem lies in the below code:
for(i = 0; i < 10; i++)
{
params.id = i;
if(pthread_create(&threads[i], NULL, hello, ¶ms));
}
Your params.id value keeps getting updated in the main thread, whereas you are passing the same pointer to all the threads.
Please create seperate memory for params by dynamically allocating it and pass it to different threads to solve the problem.
EDIT1:
Your usage of mutex to protect is also an incorrect idea. Though your mutex if used in main while setting the id also, may make the updation mutually exclusive, but you may not get your desired output. Instead of getting values from 0 .. 9 in different threads, you may get all 9s or still multiple threads may print same values.
So, using thread synchronization is not such a good idea for the output which you are expecting. If you still need to use one param variable between all threads and get output as 0 to 9 from each of the threads, better move the pthread_join into the first loop. This will ensure that each thread gets created, prints the value and then returns before the main spawns the next thread. In this case, you don't need the mutex also.
EDIT2:
As for the updated question, where it is asked that it is not necessary to print the numbers 0..9 in a sequence, the printing can be random, but only once, the problem still remains the same more or less.
Now, let's say, the value of params.id is first 0 and thread 0 got created, now, thread 0 must print it before it is updated in the main thread, else, when thread 0 accessess it, the value of params.id would have become 1 and you will never get your unique set of values. So, how to ensure that thread 0 prints it before it is updated in main, Two ways for it:
Ensure thread 0 completes execution and printing before main updates
the value
Use condition variables & signalling to ensure that main thread waits
for thread 0 to complete printing before it updates the value (Refer
to Arjun's answer below for more details)
In my honest opinion, you have selected the wrong problem for learning synchronization & shared memory. You can try this with some good problems like "Producer-Consumer", where you really need synchronization for things to work.
There are two problems:
A. You're using a lock but main is unaware of this lock.
B. A lock is not enough in this case. What you would want is for threads to cooperate by signalling each other (because you want main to not increment the variable until a thread says that it is done printing it). You can use a pthread_cond_t to achieve this (Look here to learn more about this). This boils down to the following code (basically, I added an appropriate usage of pthread_cond_t to your code, and a bunch of comments explaining what is going on):
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct params {
pthread_mutex_t mutex;
pthread_cond_t done;
int id;
};
typedef struct params params_t;
void* hello(void* arg){
int id;
/* Lock. */
pthread_mutex_lock(&(*(params_t*)(arg)).mutex);
/* Work. */
id = (*(params_t*)(arg)).id;
printf("Hello from %d\n", id);
/* Unlock and signal completion. */
pthread_mutex_unlock(&(*(params_t*)(arg)).mutex);
pthread_cond_signal (&(*(params_t*)(arg)).done);
/* After signalling `main`, the thread could actually
go on to do more work in parallel. */
}
int main() {
pthread_t threads[10];
params_t params;
pthread_mutex_init (¶ms.mutex , NULL);
pthread_cond_init (¶ms.done, NULL);
/* Obtain a lock on the parameter. */
pthread_mutex_lock (¶ms.mutex);
int i;
for(i = 0; i < 10; i++) {
/* Change the parameter (I own it). */
params.id = i;
/* Spawn a thread. */
pthread_create(&threads[i], NULL, hello, ¶ms);
/* Give up the lock, wait till thread is 'done',
then reacquire the lock. */
pthread_cond_wait (¶ms.done, ¶ms.mutex);
}
for(i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
/* Destroy all synchronization primitives. */
pthread_mutex_destroy (¶ms.mutex);
pthread_cond_destroy (¶ms.done);
return 0;
}
I see that the example you are trying is a toy program to probably learn about the POSIX thread library. In the real world, as we all know this can be done much faster without even using threads. But you already know this.
The problem is that you are modifying the params.id "unprotected" in main. This modification in main also needs to be mutex protected. You could protect this access by localizing this by creating getId() and setId() functions that would lock the mutex and protect access to the id, as follows. This will most likely still give the problem reported, since depending on when the thread calls getData() it will have one value or another. So to solve this, you could add an incrementId() function and call it from the hello() function.
struct params {
pthread_mutex_t mutex;
int id;
};
typedef struct params params_t;
int getId(params_t *p)
{
int id;
pthread_mutex_lock(&(p->mutex));
id = p->id;
pthread_mutex_unlock(&(p->mutex));
return id;
}
void setId(params_t *p, int val)
{
pthread_mutex_lock(&(p->mutex));
p->id = val;
pthread_mutex_unlock(&(p->mutex));
}
void incrementId(params_t *p)
{
pthread_mutex_lock(&(p->mutex));
p->id++;
pthread_mutex_unlock(&(p->mutex));
}
void* hello(void* arg){
params_t *p = (params_t*)(arg);
incrementId(p);
int id = getId(p);
// This could possibly be quite messy since it
// could print the data for multiple threads at once
printf("Hello from %d\n", id);
}
int main() {
pthread_t threads[10];
params_t params;
params.id = 0;
pthread_mutex_init (¶ms.mutex , NULL);
int i;
for(i = 0; i < 10; i++) {
if(pthread_create(&threads[i], NULL, hello, ¶ms));
}
for(i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
A better way to get a unique thread id would be to define the hello method as follows:
void* hello(void* arg){
pthread_t threadId = pthread_self();
printf("Hello from %d\n", threadId);
}
And to avoid the problem with all threads trying to print at once, you could do the following:
void* hello(void* arg){
params_t *p = (params_t*)(arg);
pthread_mutex_lock(&(p->mutex));
p->id++;
int id = p->id;
printf("Hello from %d\n", id);
pthread_mutex_unlock(&(p->mutex));
}
Easiest way to get the desired output would be to modify your main function as follows:
int main() {
pthread_t threads[10];
params_t params;
pthread_mutex_init (¶ms.mutex , NULL);
int i;
for(i = 0; i < 10; i++) {
params.id = i;
if(pthread_create(&threads[i], NULL, hello, ¶ms));
pthread_join(threads[i], NULL); //wait for thread to finish
}
/*for(i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}*/
return 0;
}
Output would be:
Hello from 0
...
Hello from 9
EDIT: Here's the synchronization for the corrected question:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct params {
pthread_mutex_t* mutex;
int id;
};
typedef struct params params_t;
void* hello(void* arg){
int id = 0;
params_t* params = (params_t*)arg;
if(params != 0)
{
id = params->id;
delete params;
params = 0;
}
printf("Hello from %d\n", id);
}
int main() {
pthread_t threads[10];
params_t* params = 0;
pthread_mutex_t main_mutex;
pthread_mutex_init (&main_mutex , NULL);
int i;
for(i = 0; i < 10; i++) {
params = new params_t(); //create copy of the id to pass to each thread -> each thread will have it's own copy of the id
params->id = i;
params->mutex = &main_mutex;
if(pthread_create(&threads[i], NULL, hello, params));
}
for(i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
Each thread must have it's own copy of the id so that the other threads do not modify the id before it is printed.
I'm just putting this one here to provide another solution to this problem - this one does not involve mutexes - no synchronization - no conditionals, etc.
The main dfference is that we are using pthread_detach to automatically release the thread's resources upon completion.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NUMTHREADS 10
typedef struct params {
int id;
} params_t;
void* hello(void *arg)
{
params_t *p = (params_t*)arg;
int status;
status = pthread_detach(pthread_self());
if (status !=0 )
{
printf("detaching thread\n");
abort();
}
printf("Hello from %d\n", p->id);
free(p);
return NULL;
}
int main()
{
pthread_t thread;
params_t *par;
int i, status;
for (i=0; i<NUMTHREADS; i++)
{
par = (params_t*)malloc(sizeof(params_t));
if (par == NULL)
{
printf("allocating params_t");
abort();
}
par->id = i;
status = pthread_create(&thread, NULL, hello, par);
if (status != 0)
exit(1);
}
/* DO some more work ...*/
sleep(3);
exit(0);
}
Related
I have a question about this piece of code I have. It is the classic readers-writers problem. I followed the pseudo-code found on this wikipedia page for the first problem that has writers starving. I would like to know how I would actually notice the starvation of the writers going on.
I tried putting print statements of the shared_variable in various places, but this didn't give me much insight. But maybe I just didn't understand what was going on. Would someone be able to explain to me how I could visually see the starvation happening? Thank you!
The number of attempts that the reader or writer would attempt to read or write is given as a command line argument.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
// Compile it like so: gcc assignment2.c -lpthread
// Shared variables (semaphore and integer)
static sem_t rw_mutex;
static sem_t mutex;
static int read_count = 0;
// Shared variable
int shared_variable = 0;
static void *writerAction(void *arg){
int number_attempt = *((int *) arg);
int attempt = 0;
do{
sem_wait(&rw_mutex);
shared_variable = shared_variable + 10;
sem_post(&rw_mutex);
attempt++;
}while(attempt < number_attempt);
}
static void *readerAction(void *arg){
int number_attempt = *((int *) arg);
int attempt = 0;
do{
sem_wait(&mutex);
read_count++;
// waiting to be able to read for the possible writer
if (read_count == 1 ){
sem_wait(&rw_mutex); // get the lock so that writter can't write!
}
// Release the read_count variable
sem_post(&mutex);
sem_wait(&mutex);
read_count--;
if (read_count == 0){
sem_post(&rw_mutex); // release the lock so that writter can write
}
sem_post(&mutex);
attempt++;
} while(attempt < number_attempt);
}
int main(int argc, char *argv[]) {
int number_writers = 10;
int number_readers = 500;
int reader_repeat_count = atoi(argv[2]);
int writer_repeat_count = atoi(argv[1]);
// Instantiating the threads for the writters and readers
pthread_t writer_threads[number_writers];
pthread_t reader_threads[number_readers];
// Initation of semaphores
sem_init(&rw_mutex, 0, 1);
sem_init(&mutex, 0, 1);
printf("Start creation of Readers\n");
for(int i = 0; i <number_readers; i++){
pthread_create(&reader_threads[i], NULL, readerAction, &reader_repeat_count);
}
printf("Start creation of Writers\n");
for(int i = 0; i < number_writers; i++){
pthread_create(&writer_threads[i], NULL, writerAction, &writer_repeat_count);
}
// All the actions is hapenning here
printf("Wait for Readers\n");
for(int i = 0; i < number_readers; i++){
printf("Waiting for : %d\n",i);
pthread_join(reader_threads[i], NULL);
}
printf("Wait for Writers\n");
// Collect all the writers
for(int i = 0; i < number_writers; i++){
printf("Waiting for : %d\n",i);
pthread_join(writer_threads[i], NULL);
}
// Results
printf("The shared variable is : %d\n",shared_variable);
}
First of all there is a syntax error, the return type of writerAction and readerAction should be void not void*
In order to see writer starvation you can print "writer trying to write" just before writer is trying to acquire the rw_mutex, the call to sem_wait(&rw_mutex). Add another print when the writer has updated the shared variable, inside the critical section. Add one more printf just after the the entry section of the reader. Which is this code.
// Release the read_count variable
sem_post(&mutex);
printf("reader reading shared value %d\n", shared_variable);
Now when you run the code with large repeat count, You will see "writer trying to write" then you will see a large number of reader printouts instead of the one from writer updating the shared variables, which will prove that the readers are starving the writer by not allowing it to update the variable.
The requirement for the sample application creating using pthread is given below:
A single thread is created from main using Pthread
Inside thread, Mutex is locked, a counter counts the value and while loop is incremented, While is set to the max count of 10.
after while loop finishes, the mutex is unlocked.
The above requirement I have tried implementing using pthread
Code is shown below:
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv;
int samples = 10;
int count = 0;
struct example
{
int i;
int a;
};
void *inc_x(void *x_void_ptr)
{
pthread_mutex_lock(&count_mutex);
printf("Thread is locked \n");
while(count < samples)
{
printf("inside While loop \n");
struct example *E2_ptr;
E2_ptr = (struct example *)x_void_ptr;
printf("inside thread count = %d\n",count);
E2_ptr->a = count;
E2_ptr->i = (count + 1);
count ++;
//pthread_cond_wait(&count_threshold_cv, &count_mutex);
}
pthread_mutex_unlock(&count_mutex);
printf ( "\n Test Successful for Thread\n");
pthread_exit(NULL);
}
int main()
{
int x = 100, y = 0,i = 0;
struct example *E1_ptr;
E1_ptr->a = 0;
E1_ptr->i = 0;
printf("Before\t E1_ptr->a = %d\t, E1_ptr->i = %d\n",E1_ptr->a,E1_ptr->i);
pthread_t inc_x_thread;
if(pthread_create(&inc_x_thread, NULL, inc_x, E1_ptr))
{
printf("Error creating thread\n");
}
if(pthread_join(inc_x_thread, NULL))
{
printf("Error joining thread\n");
}
for(i = 0; i<(samples-1); i++)
{
if(pthread_cond_signal(&count_threshold_cv))
{
printf("Error Signaling thread at sample = %d\n",i);
}
}
printf("after\t E1_ptr->a = %d\t, E1_ptr->i = %d\n",E1_ptr->a,E1_ptr->i);
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
pthread_exit (NULL);
return 0;
}
Doubt:
In the above code, the thread executes its function properly and exits.
Once the condition is applied, i.e. the below shown code is uncommented then,
pthread_cond_wait(&count_threshold_cv, &count_mutex);
Then the thread is stopped after 1st iteration of while loop as expected.
The signal is generated from main by the code shown below:
for(i = 0; i<(samples-1); i++)
{
if(pthread_cond_signal(&count_threshold_cv))
{
printf("Error Signaling thread at sample = %d\n",i);
}
}
observed that the signal is never sent.
Can someone please guide me, where am I going wrong. I'm a newbie to Pthreads.
Thanks in advance.
count_mutex and count_threshold_cv are not initialized, add:
int main()
{
pthread_mutex_init(&count_mutex, NULL);
pthread_cond_init(&count_threshold_cv, NULL);
//...
E1_ptr is not initialized.
There are many ways to solve it:
You can call malloc to allocate memory:
struct example *E1_ptr = malloc(sizeof(struct example));
E1_ptr->a = 0;
E1_ptr->i = 0;
or holds pointer to local variable:
struct example ex;
struct example *E1_ptr = &ex; //malloc(sizeof(struct example));
E1_ptr->a = 0;
E1_ptr->i = 0;
or
struct example ex;
ex.a = 0;
ex.i = 0;
then create thread with pthread_create(&inc_x_thread, NULL, inc_x, &ex)
pthread_cond_signal function does not wait. If a thread is blocked by condition variable pthread_cond_signal function unblocks this thread, otherwise returns immediately without waiting and does nothing. So your for loop with 10 iterations is executed as soon as possible, without any waiting for pthread_cond_wait is called.
So can rewrite your for loop to infinite loop, calling pthread_cond_signal repeatedly.
if(pthread_create(&inc_x_thread, NULL, inc_x, E1_ptr)) {
printf("Error creating thread\n");
}
while(1) { // INFINITE LOOP
if(pthread_cond_signal(&count_threshold_cv)) {
printf("Error Signaling thread at sample = %d\n",i);
}
if (taskDone) // testing global flag, if 1 break
break; // it means inc_x thread has ended
}
if(pthread_join(inc_x_thread, NULL)) { // it was pointed out in comment
printf("Error joining thread\n"); // you need to join at the end of main function
}
taskDone is global int, with 0 as default value. It is set to 1 before pthread_exit is called in inc_x function. Setting/checking taskDone should be wrapped with some synchronization mechanism, for example by adding new mutex or use count_mutex.
I have two functions initialize() and deinitialize() and each function should run only once. The structure is something similar to:
int *x;
initialize()
{
x = malloc(sizeof(int) * 10);
}
deinitialize()
{
free(x);
}
How can I ensure that only the first thread calls initialize and only the last thread calls deinitialize.
Can this be achieve without the use of mutex?
UPDATE:
Sorry for the poor information. I am actually modifying a library that contains the functions initialize() and deinitialize(). I need to make these two functions thread-safe. The users might use multiple threads and might call these functions more than once. I cannot assume that the users will call exactly once to initialize and deinitialize functions. I can only assume is that if a thread calls initialize, it will call deinitialize at some point.
The users will be using pthread library to create their different threads.
I don't know what you want to achieve, the most easiest is:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
int *x;
int running;
void initialization(void)
{
x = malloc(sizeof(int) * 10);
puts("First thread init x");
}
void deinitialization(void)
{
free(x);
puts("Last thread reset x");
}
void *handler(void *data)
{
printf("Thread started\n");
while (running) {
do_work();
}
printf("Thread exit\n");
}
int main(void)
{
pthread_t threads[3];
initialization();
for (int i = 0; i < 3; i++)
pthread_create(&threads[i], NULL, &handler, NULL);
sleep(2);
running = 0;
for (int i = 0; i < 3; i++)
pthread_join(threads[i], NULL);
deinitialization();
return 0;
}
Here you can be sure that your have called init() and deinit() only once.
UPDATE
Another variant little bit complicated, but here you also can be sure that init() called only once. Thread with id 0 can be start after 1 in this case we should wait while *x is NULL.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#define MAX_THREADS 3
int *x;
int running;
int init;
struct thread_info
{
pthread_t thread;
int id;
int first_id;
int last_id;
};
void initialization(void)
{
x = malloc(sizeof(int) * 10);
puts("First thread init x");
init = 1;
}
void deinitialization(void)
{
free(x);
puts("Last thread reset x");
}
void *handler(void *data)
{
struct thread_info *tinfo = data;
printf("Thread started\n");
if (tinfo->id == 0)
initialization();
while (!init);
/* EMPTY BODY */
while (running) {
do_work();
}
printf("Thread exit\n");
}
int main(void)
{
struct thread_info threads[MAX_THREADS] =
{
[0 ... 2].id = -1,
[0 ... 2].first_id = 0,
[0 ... 2].last_id = (MAX_THREADS - 1)
};
for (int i = 0; i < 3; i++)
pthread_create(&threads[i].thread, NULL, &handler,
((threads[i].id = i), &(threads[i])));
sleep(2);
running = 0;
for (int i = 0; i < 3; i++)
pthread_join(threads[i].thread, NULL);
deinitialization();
return 0;
}
deinit() is a little bit tricky because your last thread can be exiting and free(x) while another thread is still running and maybe use it. So I leave it after all threads is exiting.
This is the point about concurrent programming. You can never make any assumptions about the order in which the threads execute.
The exact timing of when tasks in a concurrent system are executed depend on the scheduling, and tasks need not always be executed concurrently. For example, given two tasks, T1 and T2:
T1 may be executed and finished before T2 or vice versa (serial and
sequential)
T1 and T2 may be executed alternately (serial and concurrent)
T1 and T2 may be executed simultaneously at the same instant of time
(parallel and concurrent)
I'm trying to make a simple program using pthreads, want to make 6 threads and pass index to all of them. here's the code:
#include <pthread.h>
#include <stdio.h>
#define num_students 6
void thread_starter();
int main() {
pthread_t thread1[num_students];
int i = 0;
for(i = 0; i<num_students; i++) {
int q = i;
pthread_create(&thread1[i], NULL, (void *) &thread_starter, (void *)&q);
}
sleep(1);
}
void thread_starter(void* a) {
printf("Thread %i \n", *((int*)a));
}
And the output:
Thread 2
Thread 3
Thread 2
Thread 4
Thread 5
Thread 5
why do they have commmon names? what's wrong?
Thanks
You're passing a stack address from the main thread into all the child threads. There is no guarantee when these threads will be scheduled so you have no way of knowing whether the main thread will have updated its stack variable by the time each child gets around to reading it.
To avoid this, you need to allocate memory for the data being passed to each thread.
The easiest way to do this in your example is to use another automatic variable to store the data being passed to the new threads
void thread_starter(void* a);
int main() {
pthread_t thread1[num_students];
int thread_data[num_students];
int i = 0;
for(i = 0; i<num_students; i++) {
thread_data[i] = i;
pthread_create(&thread1[i], NULL, thread_starter, &thread_data[i]);
}
sleep(1);
}
Note also that you can avoid having to cast thread_starter if you give it the correct signature in your forward declaration.
For more complex programs you may need to dynamically allocate memory for each thread instead, passing ownership of that memory to the new threads.
int main() {
pthread_t thread1[num_students];
int i = 0;
for(i = 0; i<num_students; i++) {
int* data = malloc(sizeof(*data));
*data = i;
pthread_create(&thread1[i], NULL, thread_starter, data);
}
sleep(1);
}
void thread_starter(void* a) {
printf("Thread %i \n", *((int*)a));
free(a);
}
Finally, using sleep(1) isn't a very rigorous way of ensuring that all your threads will be run. It'd be better to use pthread_join instead
for(i = 0; i<num_students; i++) {
pthread_join(thread1[i], NULL);
}
sleep is not the correct tool to wait for spawned threads, use pthread_join for this.
Your main function terminating is equivalent to calling exit for the whole program and killing all the other threads.
Try This for Variation
void thread_starter(void* a) {
// Put a sleep(1) Here and see you will get even bizarre results
printf("Thread %i \n", *((int*)a));
}
Ok the problem here is of course
the race condition at this point here
int q = i;
pthread_create(&thread1[i], NULL, (void *) &thread_starter, (void *)&q);
lets say the first thread is created and the value at q is 0
now assume that before executing the statement Here
printf("Thread %i \n", *((int*)a));
if the main thread loops further and executes this statement here
int q = i;
again, then the q value changes (because its a reference) hence the problem
well one way to avoid this is to copy this reference variable in a local variable in thread routine also use mutex.
Sorry I was on a Hurry some more tips from my side
#define num_students 6
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // A Global Mutex
Will aquire a lock Here
pthread_mutex_lock( &mutex );
printf("\n Got Mutex %d\n", i);
int q = i;
pthread_create(&thread1[i], NULL, (void *) &thread_starter, (void *)&q);
and will release the lock Here in child Routine
int i = *((int*)a);
sleep(1);
pthread_mutex_unlock( &mutex );
printf("Thread %i \n", i);
P.S - Remove un necessary Prints and Sleeps where ever not applicable
I am learning multithreading performance in C. When I tried to write a sample code, I bumped into a problem:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
typedef struct{
int a;
char b;
} args;
void* some_func (void* arg)
{
args *argsa = malloc(sizeof(args));
//copy the content of arg to argsa,
//so changes to arg in main would not affect argsa
*argsa = *(args*) arg;
int i = 10;
for (; i > 0; i--)
{
usleep (1); //to give other threads chances to cut in
printf ("This is from the thread %d\n", argsa->a);
}
free (argsa);
}
int main()
{
pthread_t thread[3];
args ss;
int index = 0;
ss.b = 's';
for (; index <3 ; index++)
{
ss.a = index;
if (pthread_create (thread+index, NULL, some_func, (void*)&ss ))
{
usleep(10);
printf ("something is wrong creating the thread");
}
}
pthread_join ( thread[0], NULL);
pthread_join ( thread[1], NULL);
pthread_join ( thread[2], NULL);
return 0;
}
I know char b in the struct is useless, but I just want to practice passing a structure.
I expect the code to print out "This is from the thread x", where x is 0, 1 or 2, alternatively. However, the code currently only gives me "This is from the thread 2" 30 times. I believe there is something wrong with
*argsa = *(args*) arg;
But I can't find a way to solve this and get the desired output.
Any help would be appreciated!
Because you are passing the same pointer to all the threads. By the time thread 0 has started, you have already incremented the value of ss.a to 1 (and then 2).
This is a bit more correct:
void* some_func (void* arg)
{
args *argsa = (args*)arg;
int i;
for (i = 0; i < 10; i++)
{
usleep (1); //to give other threads chances to cut in
printf ("This is from the thread %d\n", argsa->a);
}
}
int main()
{
pthread_t thread[3];
args ss[3];
int index;
for (index = 0; index < 3; index++)
{
ss[index].a = index;
if (pthread_create(&thread[index], NULL, some_func, &ss[index] ))
{
printf ("something is wrong creating the thread");
}
}
pthread_join ( thread[0], NULL);
pthread_join ( thread[1], NULL);
pthread_join ( thread[2], NULL);
return 0;
}
The pattern to use to solve this kind of problem is as follows:
Create a structure that will hold the parameters you want to pass to the thread.
Allocate such a structure with malloc.
Fill in the structure.
Pass the pointer to the structure to the thread.
When the thread is finished with the structure, the thread frees it.
This assumes you don't need to get any information back from the thread. If you do, you can change it so that the code that joins the thread frees the structure. That allows the structure to hold a reply as well -- you join the thread, read the response information, and then free the structure.
No special locking or synchronization is required because while the newly-created thread exists, it is the only thread that touches the structure.
Sorry guys, but I was trying to solve the same issue and I don't think a proper answer was given yet, in order to solve the problem. I tried this on my own and I came up with the following code. Now, I compiled and run it and it pretty worked as I expected, still I not that confident that the "lock in main and unlock in child process" is the most elegant solution, so I'd like to know what you think about it. Thank you very much in advance for any clarification.
Here is the code:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
typedef struct{
int a;
char b;
} args;
pthread_mutex_t lock;
void* some_func (void *arg) {
args argsa = *(args*)arg;
pthread_mutex_unlock(&lock);
printf ("This is from the thread %d\n", argsa.a);
}
int main() {
pthread_t thread[10];
args ss;
int i, index=0;
ss.b = 's';
if (pthread_mutex_init(&lock, NULL) != 0) {
printf("\n mutex init failed\n");
return 1;
}
for (index = 0; index < 10 ; index++)
{
pthread_mutex_lock(&lock);
ss.a = index;
printf("index=%d, ", ss.a);
if (pthread_create (thread+index, NULL, some_func, (void*)&ss ))
{
usleep(10);
printf ("something is wrong creating the thread");
}
}
for(i=0;i<10;i++)
pthread_join ( thread[0], NULL);
return 0;
}
Output:
#./program
index=0, This is from the thread 0
index=1, This is from the thread 1
index=2, This is from the thread 2
index=3, This is from the thread 3
index=4, This is from the thread 4
index=5, This is from the thread 5
index=6, This is from the thread 6
index=7, This is from the thread 7
index=8, This is from the thread 8
index=9, This is from the thread 9