user3685525
user3685525

Reputation: 33

My pthread is not schedualing. In C

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

Answers (3)

B Jacob
B Jacob

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

Sourav Ghosh
Sourav Ghosh

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

sonicwave
sonicwave

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

Related Questions