Go Back   MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Feb 6, 2013, 07:22 PM   #1
dude5552
macrumors newbie
 
Join Date: Feb 2013
Shared Memory thread synchronization problem

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
dude5552 is offline   0 Reply With Quote
Old Feb 6, 2013, 08:14 PM   #2
chown33
macrumors 603
 
Join Date: Aug 2009
Which language?

Post your code.


Have you read this:
https://developer.apple.com/library/...eadSafety.html
chown33 is offline   0 Reply With Quote
Old Feb 7, 2013, 04:07 AM   #3
gnasher729
macrumors G5
 
gnasher729's Avatar
 
Join Date: Nov 2005
Quote:
Originally Posted by dude5552 View Post
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.
gnasher729 is offline   0 Reply With Quote
Old Feb 7, 2013, 05:00 AM   #4
robbieduncan
Moderator
 
robbieduncan's Avatar
 
Join Date: Jul 2002
Location: London
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?
robbieduncan is offline   0 Reply With Quote
Old Feb 7, 2013, 06:19 AM   #5
ghellquist
macrumors regular
 
Join Date: Aug 2011
Location: 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
ghellquist is offline   0 Reply With Quote
Old Feb 7, 2013, 09:24 AM   #6
gnasher729
macrumors G5
 
gnasher729's Avatar
 
Join Date: Nov 2005
Quote:
Originally Posted by ghellquist View Post
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

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;
}
gnasher729 is offline   0 Reply With Quote
Old Feb 7, 2013, 12:15 PM   #7
dude5552
Thread Starter
macrumors newbie
 
Join Date: Feb 2013
Quote:
Originally Posted by chown33 View Post
Which language?

Post your code.


Have you read this:
https://developer.apple.com/library/...eadSafety.html
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...
dude5552 is offline   0 Reply With Quote
Old Feb 7, 2013, 12:41 PM   #8
robbieduncan
Moderator
 
robbieduncan's Avatar
 
Join Date: Jul 2002
Location: London
Quote:
Originally Posted by dude5552 View Post
Before i wrote in x86 64 bit assembly...
Why

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...
robbieduncan is offline   0 Reply With Quote
Old Feb 7, 2013, 01:17 PM   #9
subsonix
macrumors 68040
 
Join Date: Feb 2008
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.
subsonix is offline   0 Reply With Quote
Old Feb 7, 2013, 01:39 PM   #10
dude5552
Thread Starter
macrumors newbie
 
Join Date: Feb 2013
Quote:
Originally Posted by robbieduncan View Post
Why

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

----------

Quote:
Originally Posted by subsonix View Post
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....

----------

Quote:
Originally Posted by subsonix View Post
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....
dude5552 is offline   0 Reply With Quote
Old Feb 7, 2013, 01:44 PM   #11
subsonix
macrumors 68040
 
Join Date: Feb 2008
Quote:
Originally Posted by dude5552 View Post
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
subsonix is offline   0 Reply With Quote
Old Feb 7, 2013, 01:45 PM   #12
AlanShutko
macrumors 6502
 
Join Date: Jun 2008
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.
AlanShutko is offline   0 Reply With Quote
Old Feb 7, 2013, 02:03 PM   #13
dude5552
Thread Starter
macrumors newbie
 
Join Date: Feb 2013
Quote:
Originally Posted by subsonix View Post
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

----------

Quote:
Originally Posted by subsonix View Post
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...
dude5552 is offline   0 Reply With Quote
Old Feb 7, 2013, 02:04 PM   #14
subsonix
macrumors 68040
 
Join Date: Feb 2008
Quote:
Originally Posted by dude5552 View Post
Right ...
Now assume that i allocated a big chunk of memory g_mem1
How did you allocate g_mem1? Processes do not share address space.
subsonix is offline   0 Reply With Quote
Old Feb 7, 2013, 02:15 PM   #15
dude5552
Thread Starter
macrumors newbie
 
Join Date: Feb 2013
Quote:
Originally Posted by subsonix View Post
How did you allocate g_mem1? Processes do not share address space.
g_mem1=(UINT64)mmap(<SOMETHING HERE>);
dude5552 is offline   0 Reply With Quote
Old Feb 7, 2013, 04:43 PM   #16
ElectricSheep
macrumors 6502
 
Join Date: Feb 2004
Location: Wilmington, DE
Send a message via AIM to ElectricSheep
Quote:
Originally Posted by dude5552 View Post
g_mem1=(UINT64)mmap(<SOMETHING HERE>);
What is the <SOMETHING HERE>, because what you pass to mmap() will influence how memory is shared between two processes.
__________________
15'' MBP (early 2011) | i7 3770k Hackintosh | i7 Mac Mini (late 2012) | iPhone 5 | iPad 3 (2012) | iPad mini | MacOS X 10.9.2
ElectricSheep is offline   0 Reply With Quote
Old Feb 7, 2013, 05:14 PM   #17
ghellquist
macrumors regular
 
Join Date: Aug 2011
Location: 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
ghellquist is offline   0 Reply With Quote
Old Feb 7, 2013, 06:18 PM   #18
dude5552
Thread Starter
macrumors newbie
 
Join Date: Feb 2013
Quote:
Originally Posted by ElectricSheep View Post
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);
dude5552 is offline   0 Reply With Quote
Old Feb 7, 2013, 06:40 PM   #19
ghellquist
macrumors regular
 
Join Date: Aug 2011
Location: Stockholm Sweden
What about
MAP_PRIVATE Modifications are private (copy-on-write)?

Try MAP_SHARED instead
// Gunnar
ghellquist is offline   0 Reply With Quote
Old Feb 7, 2013, 08:11 PM   #20
dude5552
Thread Starter
macrumors newbie
 
Join Date: Feb 2013
Quote:
Originally Posted by ghellquist View Post
What about
MAP_PRIVATE Modifications are private (copy-on-write)?

Try MAP_SHARED instead
// Gunnar
So far it looks like this solved the problem...
If it does not i will let you know...
thanks a lot
dude5552 is offline   0 Reply With Quote
Old Feb 7, 2013, 09:44 PM   #21
jared_kipe
macrumors 68030
 
jared_kipe's Avatar
 
Join Date: Dec 2003
Location: Seattle
Send a message via AIM to jared_kipe
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.
jared_kipe is offline   1 Reply With Quote
Old Feb 8, 2013, 05:35 AM   #22
gnasher729
macrumors G5
 
gnasher729's Avatar
 
Join Date: Nov 2005
Quote:
Originally Posted by jared_kipe View Post
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.
gnasher729 is offline   0 Reply With Quote
Old Feb 8, 2013, 04:05 PM   #23
jared_kipe
macrumors 68030
 
jared_kipe's Avatar
 
Join Date: Dec 2003
Location: Seattle
Send a message via AIM to jared_kipe
Quote:
Originally Posted by gnasher729 View Post
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'..
jared_kipe is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Similar Threads
thread Thread Starter Forum Replies Last Post
Iphone 5 Synchronization Problem With An External Speaker tanweerhasan iPhone Tips, Help and Troubleshooting 1 Jan 10, 2014 08:49 AM
IOS7, Shared Streams, and Video problem psneddon iCloud and Apple Services 1 Oct 30, 2013 01:31 AM
How much shared memory intel iris? mankymanning MacBook Pro 2 Oct 27, 2013 09:24 AM
Shared Photo Stream Problem... please help hunter2k9 iOS 7 2 Oct 1, 2013 10:22 PM
MBA 2012: maximum shared memory with HD4000? Dwee8le MacBook Air 9 Jun 15, 2012 06:03 PM

Forum Jump

All times are GMT -5. The time now is 01:48 AM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Copyright 2002-2013, MacRumors.com, LLC