Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

dude5552

macrumors newbie
Original poster
Feb 6, 2013
7
0
I have 2 global variables var1 and var2. I init them to 0 at the beginning. Then i start two threads t0 and t1 and to synchronize their execution on t0 i am incrementing var2 and waiting for var1 to become 10 and on t1 i am incrementing var1 and waiting for var2 to become 10 .. Since both t0 and t1 are incrementing var1 and var2 while waiting for the other to become 10 ...
What i have noticed is that for t0 var1 is always 0 and for t1 var2 is always 0 so they wait on each other forever...
Does anyone have an idea why?
I start both threads t0 and t1 at the same time...t0 is running on core 0 and t1 is runnning on core 1 in a multiprocessor setup..
I tried to print values var1 and var2 at different intervals .. i always find t0 sees var1 =0 and t1 finds var2=0...

thanks
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
I have 2 global variables var1 and var2. I init them to 0 at the beginning. Then i start two threads t0 and t1 and to synchronize their execution on t0 i am incrementing var2 and waiting for var1 to become 10 and on t1 i am incrementing var1 and waiting for var2 to become 10 .. Since both t0 and t1 are incrementing var1 and var2 while waiting for the other to become 10 ...
What i have noticed is that for t0 var1 is always 0 and for t1 var2 is always 0 so they wait on each other forever...
Does anyone have an idea why?
I start both threads t0 and t1 at the same time...t0 is running on core 0 and t1 is runnning on core 1 in a multiprocessor setup..
I tried to print values var1 and var2 at different intervals .. i always find t0 sees var1 =0 and t1 finds var2=0...

Multithreading is difficult, and so is reading other people's minds. I am quite good at the former, but really bad at the latter, so I have no idea what you are doing wrong. You seem to be bad at multithreading and good at reading minds, or you would have written something that actually could tell us what you are doing and what you are doing wrong.
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
How are your threads sharing these variables? From your description is sounds like they aren't. Even if they are how are you guaranteeing atomicity of operations?
 

ghellquist

macrumors regular
Aug 21, 2011
146
5
Stockholm Sweden
I think we ought to wait for the OP answering what code he has written.

Basically, it is about a concept often called thread-safe. It has several part, but the OP got bitten really early on. Good thing, because these errors can be among the really difficult ones to iron out. The system simply behaves in unpredictable ways.

Assume we have a variable var1 defined as:
...
int var1;
...

And then add two threads t0 and t1 reading and writing to that variable.

One of the thread might have this code snippet.

...
while ( true)
{
if (var1 > 10)
{
.... do something
}
... do some other things
}

The compiler "knows" that inside the while loop, no-one modifies var1, so it can temporarily hold the value inside a register. There is no guarantee that if another thread modifes var1, that this thread will notice it.

In c the way to tell the compiler to at least consider this situation is by adding a little something to the definition:

...
volatile int var1;
...

the little word volatile is an order to the compiler that some "other hardware" might modify the variable and that seemingly meanigless tests should not be optimized out. This is not really supposed to be used for thread synchronization, often it will simply make things work. (That is, until you end up on a compiler / hardware where this is not true). One reason why it might not work is that any operation, say

...
var1++;
...

is not guaranteed to be atomic. With atomic operations we mean operatins that are done to completion without beeing interrupted in the middle. On many architectures var1++ happens to be atomic for ints, but you actually have to check your compiler and hardware.

It cold happen that if two threads does var1++ at the same time the value is not incremented twice, but could instead be totally trashed. Most often it will actually work, but once in a time it might only increment once. And in very special circumstances, it might instead end up having some other value.

In objective-c, there is the volatile keyword, but again it is not thread-safe, in that two threads updating the same variable will not be guaranteed a result.

The solution instead, is given in the first reply where there are references to the atomic, threadsafe primitives that you should use.


// Gunnar
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
I think we ought to wait for the OP answering what code he has written.

Not going to happen. Both the waiting and the answering :D

I wouldn't be surprised if he did this:


Code:
void f (void)
{
   int x1 = 0, x2 = 0;
   while (x2 != 10) ++x1;
}

void g (void)
{
   int x1 = 0, x2 = 0;
   while (x1 != 10) ++x2;
}
 

dude5552

macrumors newbie
Original poster
Feb 6, 2013
7
0

Before i wrote in x86 64 bit assembly...
; assume the memory pointed to by r10 is in allocated space
; for t0 thread executed by core 0
start_t0:

T0BARRIER0:
inc DWORD [r10]
cmp DWORD [r11], 10
jle T0BARRIER0
mov r13, [r12]
cmp DWORD [r10], 10
jle T0BARRIER0

; move further

; some other things

; For t1 thread executed by core 1
start_t1:

T1BARRIER0:
inc DWORD [r11]
cmp DWORD [r10], 10
jle T1BARRIER0
cmp DWORD [r11], 10
jle T1BARRIER0

; move on after sychronize
; what i found is that memory location pointed to by DWORD [r10] is always
; 0 for t1 so it gets stuck and DWORD[r11] is 0 for t0
; why would sychronization be a problem since register are per core
; one core is not using other cores register they are only looking at a memory
; location to go > 10 which is incremented by other core
; i have made sure that each core hits these loops...
 

subsonix

macrumors 68040
Feb 2, 2008
3,551
79
When ever two threads use the same variable you need to use a locking mechanism or the result is going to be unpredictable, in a case where you use a threading library such as pthreads there are mutex locks for this.
 

dude5552

macrumors newbie
Original poster
Feb 6, 2013
7
0
Why :confused:

Some points:

1) Post full code that can actually be compiled and tested
2) Use the code tags :)
3) You're "variables" seem to be registers. These are core local...

Because this code is sitting in the middle of a whole bunch of code...

Because of the nature of the code i have to stick to assembly....

----------

When ever two threads use the same variable you need to use a locking mechanism or the result is going to be unpredictable, in a case where you use a threading library such as pthreads there are mutex locks for this.

I am using fork to create threads...
Is there a problem with that ... I though underneath it all it is Unix BSD related code right....

----------

When ever two threads use the same variable you need to use a locking mechanism or the result is going to be unpredictable, in a case where you use a threading library such as pthreads there are mutex locks for this.

Besidges I am not sharing variables... r10 and r11 belong to individual CPU registers either core 0 or core 1 respectively... they are only pointing to locations which are shared....
 

subsonix

macrumors 68040
Feb 2, 2008
3,551
79
I am using fork to create threads...
Is there a problem with that ... I though underneath it all it is Unix BSD related code right....

Besidges I am not sharing variables... r10 and r11 below to individual CPU registers... they are only pointing to locations which are shared....

If you use fork() then they are not threads, but processes. Threads share address space, processes don't. In regards to your second paragraph, a shared resource is probably a better term. You need to make sure that each process handles the resource in one atomic operation, hence the lock. Doing this in assembly however, means that you are on your own as far as I'm concerned lol.

If you are interested, this is how gcc implements a mutex lock:

http://comsci.liu.edu/~jrodriguez/testandset2.html
 

AlanShutko

macrumors 6502a
Jun 2, 2008
804
214
Fork does not create threads. It creates separate processes which receive a copy of memory from before the fork but is separate after that, so changes made in one process will not be seen in the other.
 

dude5552

macrumors newbie
Original poster
Feb 6, 2013
7
0
If you use fork() then they are not threads, but processes. Threads share address space, processes don't. In regards to your second paragraph, a shared resource is probably a better term. You need to make sure that each process handles the resource in one atomic operation, hence the lock. Doing this in assembly however, means that you are on your own as far as I'm concerned lol.

If you are interested, this is how gcc implements a mutex lock:

http://comsci.liu.edu/~jrodriguez/testandset2.html

Right ...
Now assume that i allocated a big chunk of memory g_mem1
then i do a fork ()
now i make register r10 to point to g_mem1 + 32
r11 g_mem1 + 64

this for core 0
then it sits in T0BARRIER0

similarly i do another fork ()
now i make register r10 to point to g_mem1 + 32
r11 g_mem1 + 64

now goes and sits in T1BARRIER0

At this point r10 and r11 are being incremented ....
at some point both should be > 10 right...

However it doesnt ... It sits in infinite loop

----------

If you use fork() then they are not threads, but processes. Threads share address space, processes don't. In regards to your second paragraph, a shared resource is probably a better term. You need to make sure that each process handles the resource in one atomic operation, hence the lock. Doing this in assembly however, means that you are on your own as far as I'm concerned lol.

If you are interested, this is how gcc implements a mutex lock:

http://comsci.liu.edu/~jrodriguez/testandset2.html

Here is the fun :)

I can use mutex lock however since it is a OS facility, an OS code which i dont have much control over, i cannot maintain concurrency.
I cannot guarantee that after they sychronize they maybe several cpu cycles off... of each other...
i need to keep both core 0 and core 1 concurrently executing...
 

ghellquist

macrumors regular
Aug 21, 2011
146
5
Stockholm Sweden
Divide the problem.

First, do the two processes actually share memory?

Let t0 store a magic number next to its variable. Check in t1 if that magic number is there. If not, the problem clearly is that they are not sharing memory.

// Gunnar
 

dude5552

macrumors newbie
Original poster
Feb 6, 2013
7
0
What is the <SOMETHING HERE>, because what you pass to mmap() will influence how memory is shared between two processes.

g_mem1 = (UINT64)mmap((LPVOID)req_addr, g_reqsz, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0);
 

jared_kipe

macrumors 68030
Dec 8, 2003
2,967
1
Seattle
I have to ask...
What are you doing that needs to be this low level??


I have a poor imagination when it comes to cases when you are running on a platform that has gcc and the processor speed and optimizations to make C possible, but you prefer to do multi-threading from the ground up in assembly. I believe that C (with optimizations) can, and will, write better assembly then 99% of programmers could ever come up with.
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
I have to ask...
What are you doing that needs to be this low level??


I have a poor imagination when it comes to cases when you are running on a platform that has gcc and the processor speed and optimizations to make C possible, but you prefer to do multi-threading from the ground up in assembly. I believe that C (with optimizations) can, and will, write better assembly then 99% of programmers could ever come up with.

I wouldn't say the compiler would produce better assembler code than I could, given an infinite amount of time, but I can write ten times better algorithms in a high level language than I could in assembler. And I can call code written by others who spent ten times more time on it than I could reasonably justify.
 

jared_kipe

macrumors 68030
Dec 8, 2003
2,967
1
Seattle
I wouldn't say the compiler would produce better assembler code than I could, given an infinite amount of time, but I can write ten times better algorithms in a high level language than I could in assembler. And I can call code written by others who spent ten times more time on it than I could reasonably justify.

One could argue that 'maintainable' is 'better'..
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.