Do you have a question? Post it now! No Registration Necessary
December 7, 2010, 6:28 pm

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 ?
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

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

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

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


Re: Setting a global variable into a thread

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 :(
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

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

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

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).

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

Re: Setting a global variable into a thread

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.
Site Timeline
- » Prefered hardware
- — Next thread in » Embedded Linux
-
- » JFFS2 atomic write?
- — Previous thread in » Embedded Linux
-
- » Crosscompiling for ARM: reloc type R_ARM_ABS32 is not supported for PIC - ...
- — Newest thread in » Embedded Linux
-
- » pemohon
- — The site's Newest Thread. Posted in » Electronics Computer-Aided Design
-