2
votes

In my code, I want to create three threads one by one. So I use a global variable to control this. But it does not work as I design. It is blocked on a while loop. Here is my code:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
int startb = 0, startc=0;

.......

int main(int argc, char* argv[]){
    pthread_t ida,idb,idc;
    int result;

    pthread_key_create(&stKey, TsdFree);

    result = pthread_create(&idb, NULL, (void*)printB, NULL);
    if(0 != result)
    {
        printf("create thread B error\n");
    }
    while (1 != startb); /*block here*/
    result = pthread_create(&idc, NULL, (void*)printC, NULL);
........
}

Thread B:

void  printB(void* para)
{
   for(int i=0; i<2;++i)
   {
       pthread_mutex_lock(&mutex);
       startb = 1;
       pthread_cond_wait(&conda, &mutex);
       pthread_mutex_unlock(&mutex);
      printf("B\n");
       pthread_mutex_lock(&mutex);
       pthread_cond_signal(&condb);
       pthread_mutex_unlock(&mutex);
   }
    pthread_exit(0);
}

I use gdb to see the value of the variable of startb. it turns out that the value of startb has already been 1:

Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 0x000000000040068b in main (argc=, argv=) at pthread.c:57 57 while (1 != startb); (gdb) bt

0 0x000000000040068b in main (argc=, argv=) at pthread.c:57 (gdb) p startb $1 = 1 (gdb) bt

0 0x000000000040068b in main (argc=, argv=) at pthread.c:57 (gdb) c

Continuing.

The Call stack of these threads:

main:

[<0>] exit_to_usermode_loop+0x59/0xd0
[<0>] prepare_exit_to_usermode+0x77/0x80
[<0>] retint_user+0x8/0x8
[<0>] 0xffffffffffffffff

thread B:

[<0>] futex_wait_queue_me+0xc4/0x120
[<0>] futex_wait+0x10a/0x250
[<0>] do_futex+0x325/0x500
[<0>] SyS_futex+0x13b/0x180
[<0>] do_syscall_64+0x73/0x130
[<0>] entry_SYSCALL_64_after_hwframe+0x3d/0xa2
[<0>] 0xffffffffffffffff

Can anyone tell me the reason?

1
Please add the declaration of startb so we can help better. - Josef Ginerman
@iosi G the startb is a global variable. The declaration has been added. - hohl
regarding: void printB(void* para) The signature of a posix thread is void * printB( void* para) Note the return type is void* not void - user3629249
OT: in main() when the parameters are not used, avoid the two warnings from the compiler about unused parameters by using the signature: int main( void ) - user3629249
the posted code causes the compiler to output MANY warning and error messages. When compiling, always enable the warnings, then fix those warnings. ( for gcc, at a minimum use: -Wall -Wextra -Wconversion -pedantic -std=gnu11 ) Note other compilers use different options to perform the same thing - user3629249

1 Answers

5
votes

You can't use simple variables for inter thread communication. As is stands, the compiler will see that in the loop

while (1 != startb); /*block here*/

the value of startb never is modified, and hence will legally rewrite it internally to

if( 1 != startb ){
    while( true );
}

A loop waiting for some externally set flag is called a Spinlock and a proper spinlock implementation must take care to use Atomic Semanticity and Memory Barriers.

However for what you intend to do, the right choice is the use of a Condition Variable, a construct that's perfectly well supported by pthreads, which you're already attempt do use, but do it improperly.