Reputation: 33
I have a program that takes the argument then dynamically allocating space for multiple pthread_t
(array of pthread), then pthread_create()
to load function.
The problem is that my first thread just doesn't stop running. My second thread will not even create before my first thread finish the whole process. How do I solve this problem?
Here is a simple code to demonstrate my problem
#include <stdio.h>
#include <pthread.h>
pthread_t *ptr;
int num;
void* func(int id)
{
while(1)
printf("%d\n", id);
}
int main(int argc, char *argv[])
{
int i;
num = atoi(argv[1]); //assuming arguments are always valid
ptr = malloc(sizeof(pthread_t)*num);
for(i = 0; i < num; i++)
pthread_create(&ptr[i], NULL, func(i), NULL);
//free allocated space
return 0;
}
My problem is that 0
is always printed, I never see 1
.
My guess is that ptr[1] never get the chance to initialize itself, so the thread doesn't exists. So it will not get it's cpu share.
Isn't the program itself has 1 main thread. After some process time, cpu should switch back to the main thread then pthread_create the second thread.It never happens. I'm just wondering why.
I'm a newbie in C, and this is my first time doing pthread. So please give advice that suits my level. Thank you.
Thanks to all the great advices, I have changed my code to:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
int num;
pthread_t *ptr;
void* func(void* id)
{
int *c;
c = (int*)id;
while(1)
if(c)
printf("%d\n", *c);
}
int main(int argc, char *argv[])
{
int i;
num = atoi(argv[1]);
ptr = malloc(sizeof(pthread_t)*num);
for(i = 0; i < num; i++)
pthread_create(&ptr[i], NULL, func, (void*)&i);
for(i = 0; i < num; i++)
pthread_join(ptr[i], NULL);
return 0;
}
However, I still only see 0
. I created the thread now right?
Upvotes: 1
Views: 1025
Reputation: 389
for(i = 0; i < num; i++)
pthread_create(&ptr[i], NULL, func, (void*)&i)
The thread creation order is unpredictable. So thread-one may get initialized with thread-two's argument. Its not safe to use same variables while creating multiple threads in a loop.
As indicated in the above answer, use separate variables for all threads.
for(i = 0; i < num; i++)
{
index[i] = i;
}
for(i = 0; i < num; i++)
{
pthread_create(&ptr[i], NULL, func, (void*)&index[i]);
}
Upvotes: 1
Reputation: 134396
Please have a look at the man page of pthread_create
.
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
The pthread_create() function starts a new thread in the calling process.The new thread starts execution by invoking start_routine(). arg is passed as the sole argument of start_routine().
The correct way to supply arguments to the thread function is to use the void *args
[which is NULL
in your case].
You can do something like
void* func(void * id)
{
int c;
if (id)
c = (int)*id;
while(1)
printf("%d\n", c);
}
and
pthread_create(&ptr[i], NULL, func, (void *)&i);
EDIT:
As stated by David, to make sure the main()
keeps on running as long as the thread functions are not terminted, you might consider to add the following
pthread_join(ptr[i], NULL)
The thread execution order is entirely dependent how scheduler runs individual threads and hence the order of operations is not guranted [includes the increment of i
as a part of main()
]. Try something like
Working code:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
void* func(void* id)
{
int *c;
c = (int*)id;
// while(1) //removing infinite loop for ease of o/p
if(c)
printf("%d\n", *c);
}
int main(int argc, char *argv[])
{
int i = 0;
int *index = NULL;
int num;
pthread_t *ptr;
if (argv[1])
num = atoi(argv[1]);
index = calloc (num, sizeof (int));
for(i = 0; i < num; i++)
{
index[i] = i;
}
ptr = malloc(sizeof(pthread_t)*num);
for(i = 0; i < num; i++)
{
pthread_create(&ptr[i], NULL, func, (void*)&index[i]);
}
for(i = 0; i < num; i++)
pthread_join(ptr[i], NULL);
return 0;
}
Upvotes: 3
Reputation: 6102
Just to point out whats actually happening with your code - to work as intended, pthread_create()
needs a pointer to the function that should run in a new thread.
What you are doing is:
pthread_create(&ptr[i], NULL, func(i), NULL);
Instead of passing func
as a pointer, you call the function directly. Since the arguments to pthread_create()
need to be evaluated before pthread_create()
can be called, func()
is thus run - but in your main thread, before even getting around to starting a new thread. And since func()
consists of an infinite loop, you'll never get around to seeing anything but the output of func(0)
.
To call pthread_create()
correctly, use a function pointer to it, which you can very easily get by just leaving out the ()
part (as pointed out by some of the other answers, you can pass your i
argument to func()
in the fourth argument to pthread_create()
). That is:
pthread_create(&ptr[i], NULL, func, (void*)i);
Also, other things to note (as pointed out by the other answers), you should change func()
to take a void*
argument, and make sure that your main thread keeps running after spawning the threads - either by entering an infinite loop of sorts, or by calling pthread_join()
to wait for the spawned threads to terminate
Upvotes: 2