Setting a global variable into a thread

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
Hi
   I have a global variable (my_var) initialized to zero and from the
main thread another thread is created which only sets the global
variable to one. After creating the secondary thread, the main thread
waits for the global variable to be set to one like this:

while (0 == my_var);

Even if the global variable is set in the secondary thread, the main
thread remains blocked forever in the while loop. If I use instead:

while (0 == my_var)
{
  sleep(1);
}

the main thread detects that the global variable has been set. Could
someone explain what happens in the first case and why the global
variable is not detected when it is set ?

Re: Setting a global variable into a thread
Quoted text here. Click to load it


int local_var;

while (0 == local_var)
 {
   sleep(1);

   rw_block(my_var);

        local_var = my_var;

   rw_unblock(my_var);

}

Re: Setting a global variable into a thread
Quoted text here. Click to load it
Ooops

int local_var = 0;

 while (0 == local_var)
  {
    sleep(1);

    write_block(my_var);
            local_var = my_var;
    write_unblock(my_var);
 }

The same is true in other places where you use this variable.

Re: Setting a global variable into a thread
Quoted text here. Click to load it

What's in your "write_block" and "write_unblock" functions/macros?

And how is this better than making my_var volatile?

There are times when rtos-style locking and synchronisation tools are
important, and times when they are way over-kill.  If he wanted an rtos
solution, my_var would be a semaphore.


Re: Setting a global variable into a thread
Quoted text here. Click to load it
Just example.


Not work.


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <stdarg.h>
#include <pthread.h>

sem_t a, b;
int global = 10;


void *one(void *arg __attribute__((unused))) {

    int local;

     do {
         sem_wait(&b);
         local = global--;
         printf("A = %d\n", local);
         sem_post(&a);
    } while (local > 0);

    pthread_exit(NULL);
}

void *two(void *arg __attribute__((unused))) {

    int local;

    do {
        sem_wait(&a);
        local = global--;
        printf("B = %d\n",local);
        sem_post(&b);
    } while (local > 0);

    pthread_exit(NULL);
}

int main(void) {

    pthread_t pth[2];
    pthread_attr_t pattr;

    pthread_attr_init(&pattr);
    pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);

    sem_init(&a, 0, 0);
    sem_init(&b, 0, 1);

    pthread_create(&pth[0], &pattr, &one, NULL);
    pthread_create(&pth[1], &pattr, &two, NULL);

    pthread_detach(pth[0]);
    pthread_detach(pth[1]);

    sem_destroy (&a);
    sem_destroy (&b);

 return 0;
}

Re: Setting a global variable into a thread
Quoted text here. Click to load it

My experience with this sort of thing is mostly with small
microcontrollers, rather than Linux - most of my Linux programming is in
Python rather than C, which handles this sort of thing differently.

Can you tell me /why/ this would not work:

static volatile int my_var;

void threadOne(void) {
    while (0 == my_var) ;
    doSomething();
}

void threadTwo(void) {
    doSomething();
    my_var = 1;
    doSomething();
}


Obviously the first thread will busy-wait in the while loop, which is
seldom a good idea.  But as long as priorities and/or SMP allow
threadTwo to run, it will work.

mvh.,

David



Quoted text here. Click to load it


Re: Setting a global variable into a thread
Quoted text here. Click to load it
Or better;

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <stdarg.h>
#include <pthread.h>

sem_t a, b;
int global = 10;


void *one(void *arg __attribute__((unused))) {

    int local;

     do {
         sem_wait(&b);
         local = global--;
         printf("A = %d\n", local);
         sem_post(&a);
    } while (local >= 0);

    pthread_exit(NULL);
}

void *two(void *arg __attribute__((unused))) {

    int local;

    do {
        sem_wait(&a);
        local = global--;
        printf("B = %d\n",local);
        sem_post(&b);
    } while (local >= 0);

    pthread_exit(NULL);
}

int main(void) {

    pthread_t pth[2];
    pthread_attr_t pattr;

    pthread_attr_init(&pattr);
    pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);

    sem_init(&a, 0, 0);
    sem_init(&b, 0, 1);

    pthread_create(&pth[0], &pattr, &one, NULL);
    pthread_create(&pth[1], &pattr, &two, NULL);

    pthread_join(pth[0], (void **)&one);
    pthread_join(pth[0], (void **)&two);

    sem_destroy (&a);
    sem_destroy (&b);

 return 0;
}


Somehow, the extra cycles, can not find where. :(


Re: Setting a global variable into a thread
The truth is that if he wants to synchronize the threads this way he
should use proper pthreads API (cond vars, sems, spin locks etc.
depending on the requirements).
If this var has some "other purpose", then the right way is to make it
volatile AND use the atomic incrementing/ API that gcc provides (e.g.
__sync_fetch_and_add)

Asking such questions without defining the actual purpose of the code
always leads to flooding with almost no usable info :(

Re: Setting a global variable into a thread
Quoted text here. Click to load it

Did you remember to declare the variable 'volatile'?

--

Tauno Voipio
tauno voipio (at) iki fi


Re: Setting a global variable into a thread
Quoted text here. Click to load it

Indeed, if the global variable is declared volatile, the main thread
detects when the global variable is set without using sleep in the
while loop. It seems that the compiler optimizations mess something.
Thank you for your help.

Re: Setting a global variable into a thread
Quoted text here. Click to load it

You misunderstand - the compiler did not "mess something up".  /You/
messed up.  This is exactly the sort of thing volatile is used for, and
you need to read about and understand "volatile" before writing another
line of your multi-threaded code - otherwise you will have a lot more
problems down the line.


Re: Setting a global variable into a thread
Quoted text here. Click to load it

Well, I have checked that if my program is compiled with optimizations
turn off (-O0) the global variable change is detected without needing
to be declared volatile, while with optimizations turned on (-O3) the
global variable change is not detected.
Here is the program I have used for these tests:

char test 3D% 0;//should be declared volatile

void* thread_starter(void *data)
{
    test 3D% 1;
    syslog(LOG_INFO, "test is set");
    return NULL;
}

int main()
{
    pthread_t tid;
    void *ret_val 3D% NULL;

    if (0 !3D% pthread_create(&tid, NULL, thread_starter, NULL))
    {
        perror("pthread_create");
        return -1;
    }

    while (0 3D%3D test);

    if (0 !3D% pthread_join(tid, &ret_val))
    {
        perror("pthread_join");
        return -1;
    }
        return 0;
}

I am aware about synchronization mechanisms for threads, but this
simple situation doesn't need in my opinion such mechanisms.

Re: Setting a global variable into a thread
Quoted text here. Click to load it


If your code works when not optimised, but fails when optimised, then
your code is broken.

Re-read that last sentence, and think about it.


A compiler's job is to generate object code that will run according to
your source code.  Normally it will try to generate the best object code
it can - optimisation flags are just hints as to how hard it should try.
  Higher optimisation settings do not affect the correctness of this
process (assuming, of course, that you don't hit a bug in the compiler).
  But higher optimisation settings are less forgiving of errors in the
source code.


When "test" is declared without "volatile", then the compiler can make
assumptions about when "test" can change.  That's the way C works.  The
compiler uses these assumptions to generate better code when optimising,
such as only reading it once at the start of the "while" loop.  If that
is not the functionality you wanted, then you have to tell the compiler
what you /do/ want - you want "test" to be "volatile".



(It is seldom worth using -O3 - it may even slow code down by making it
bigger.  Use -O2, and if you want particular extra optimisations for
particular code, add the flags explicitly).



Quoted text here. Click to load it

I agree here - making "test" volatile is the appropriate fix for this
program.

Re: Setting a global variable into a thread

[skip]
Quoted text here. Click to load it

  while (NULL != &test  && 0 == test )

 :)

Re: Setting a global variable into a thread
Quoted text here. Click to load it

"&test" cannot be null - "test" a file scope variable.



Re: Setting a global variable into a thread
Quoted text here. Click to load it

It does.
If synchronizing is what you intend to do you should do it the right
way.
Otherwise a "simple solution" like this can show up in a week and lead
to a LOT of trouble (beside being hard to find in many cases).
Also think about running this code on a different platform/
architecture.
Is there a guarantee it will work? NO!
Use pthreads syncs when you want to sync threads.
That will save you a lot of stress in the best case and money/
reputation/both in the worst.

Re: Setting a global variable into a thread
Very bad idea.

Use semaphores (e.g. pthread_mutex).

-Michael

Site Timeline