2

I am facing a problem in multi-threading. Please consider the following code:

#include<stdio.h>
#include<pthread.h>

void* functionA(void*);
void* functionB(void*);


int main()
{   
    pthread_t tid[2];
    pthread_attr_t arg;

    for(int i = 0; i<2; ++i)
    {
        pthread_attr_init(&arg);

        if(i == 0)
        {
            int x = 0;  
            pthread_create(&tid[i], &arg, functionA, (void*)&x);
        }

        else if(i == 1)
        {
            int x = 6;  
            pthread_create(&tid[i], &arg, functionB, (void*)&x);
        }
    }

 // wait for both threads to finish execution...    
 pthread_join(tid[0], NULL);
 pthread_join(tid[1], NULL);

 return 0;
 }


//.........................DEFINATIONS........................

void* functionA(void* x)
{
    int Index = *((int*)x);
    printf("First: %d\n",Index);    //..................... LINE M
}


void* functionB(void* x)
{
    int Index = *((int*)x);
    printf("Second: %d\n",Index);   //....................... LINE N
}

Now I believe that functionA will start its execution first, because ofcourse thread for functionA will be created first in for loop, so according to me the output should be:

  First: 0                         (from Line M)
  Second: 6                        (from Line N)

but the actual output is,

  Second: 6
  First: 6

Now I am really surprised to see this, and I don't know what's happening. Not only secondFunction start its execution first, but also both the functions are showing same value i.e. 6, and it doesn't make sense to me. Can anyone please Explain me what is going on here???? Thanks in advance...

jww
  • 97,681
  • 90
  • 411
  • 885
Muzahir Hussain
  • 1,009
  • 2
  • 16
  • 35
  • 6
    `x` goes out of scope as soon as you create your thread, so your code is exhibiting UB. – Paul R Jan 29 '16 at 12:35
  • Try doing this in Your threads: `printf("%p\n", x);`, I guess, You will see, that the pointer is the same for both threads, because Your `int x = 0/6;` are in local scope, so they may end up allocated at the same address. – Roman Hocke Jan 29 '16 at 12:40
  • 2
    So you're using threads, but you're expecting a particular order of execution between them? What do you suppose the difference between starting a thread and calling a method is? – davmac Jan 29 '16 at 12:44
  • @Roman Hocke: Yes I got your point, Thanks :) – Muzahir Hussain Jan 29 '16 at 12:54
  • Possible duplicate of [pthread execution on linux](https://stackoverflow.com/questions/4991470/pthread-execution-on-linux), [Pthread Run a thread right after it's creation](https://stackoverflow.com/q/12536649/608639), etc. – jww Aug 14 '19 at 12:53

4 Answers4

3

two things

1) Here x variable scope is limited to that if block only. so in your thread function when you are accessing that pointer its scope is gone So you are accessing illegal memory in thread function which is wrong and it will create undefined behavior.

In response to your one comment

so is there any way that instead of variable, I can directly send a constant number, for example pthread_create(&tid[i], &arg, functionA, 6) ??

POSIX threads is a C API. C does not provide language facilities like copy constructors and so it is not possible to copy any object by value.

You need to always pass something by pointers only.

2) The priority of execuattion of threads is totaly OS and schedular dependednd you can not assume on the sequence of those threads.

Still you want some synchronisation between threads then use mutex, conditional variable etc..

Jeegar Patel
  • 26,264
  • 51
  • 149
  • 222
2

You're passing pointers to short-lived local variables into the threads, causing undefined behavior as soon as those scopes exit. Probably both threads see the same address to x.

The most obvious fix would be to use a higher scope for the variables, and have an array with an integer per thread:

 pthread_t tid[2];
 pthread_attr_t arg;
 int x[2] = { 0, 6 };
 void * (*func[])(void *) = { functionA, functionB };

 for(int i = 0; i < 2; ++i)
 {
     pthread_attr_init(&arg);
     pthread_create(&tid[i], &arg, func[i], &x[i]);
 }

 // wait for both threads to finish execution...    
 pthread_join(tid[0], NULL);
 pthread_join(tid[1], NULL);

This works since the x array will live past the calls to pthread_join(). Also no need to cast the pointer, int * converts automatically to void * in C.

Also your assumption about the order in which the threads start is false, there are no such guarantees.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • so is there any way that instead of variable, I can directly send a constant number, for example pthread_create(&tid[i], &arg, functionA, 6) ?? – Muzahir Hussain Jan 29 '16 at 12:42
  • 1
    @MuzahirHussain: You can `malloc` a buffer for the variable right before launching the thread, pass a pointer to that buffer to the thread and let the thread itself `free` the buffer, once it's done using it. – datenwolf Jan 29 '16 at 12:47
  • 1
    the declaration of the array of function pointers is not correct. The functions return a `void*` not `void` so the declaration needs to be similar to: `void *(*func[])(void *) = { functionA, functionB };` – user3629249 Jan 30 '16 at 18:17
  • @user3629249 Thanks, fixed! – unwind Feb 04 '16 at 12:37
2

There is no guarantee in which order they will run. When creating the thread the operating system's scheduler will register the new thread and run it whenever it has time. Based on priority and other hings on the system it might pick them in any order, i.e. interrupt the main thread and start one of the others, or run the main thread till the join and then start any other thread.

Likely you're testing on a multi-core system. Then those might even run in parallel at the same time, but for some reason one or the other might be faster (maybe data from the second is in a cache whereas the first has to fetch data from memory?)

Long story short: There is no guarantee whatsoever.

If you need a specific order you can use locks (i.e. mutexes) to enforce synchronisation or you might set priority (see setpriority()) or enforce real-time scheduling (sched_setscheduler()) but then you really should understand your operating system.

johannes
  • 15,807
  • 3
  • 44
  • 57
0

I believe that functionA will start its execution first, because ofcourse thread for functionA will be created first in for loop

This assumption is not correct that is dependent on thread scheduling that control by OS.

If you want see correct output declare two variable in main() function scope (before for loop)

int x = 0;  
int y = 6;  

and also make change in

pthread_create(&tid[i], &arg, functionA, (void*)&x);
 pthread_create(&tid[i], &arg, functionB, (void*)&y);

By doing this you get at least correct output.

Mohan
  • 1,871
  • 21
  • 34