Need help with communication between multiple threads
Sean Kelly
sean at f4.ca
Tue Feb 20 17:49:31 PST 2007
Chad J wrote:
> kris wrote:
>>
>> Basicially, you need to protect the value from contention between two
>> threads. There are a number of ways to do this:
>>
>> 1) using native D facilities via the synchronized keyword: expose a
>> getter and setter method, and have them both synch on the same
>> object/lock. This is a fairly heavyweight resolution, but it would work.
>>
>
> So would something like this do the trick?
>
> class Mutex
> {
> uint pointlessVariable;
> }
> Mutex mutex;
>
> uint m_value = 42; // The thing to be protected.
> uint value() // getter
> {
> synchronized(mutex)
> return m_value;
> }
> uint value(uint newbie) // setter
> {
> synchronized(mutex)
> m_value = newbie;
>
> return newbie;
> }
>
> Or am I supposed to do something else like put m_value inside the mutex
> class?
You could use synchronized with no arguments and everything will work
file. The default behavior for free functions is to synchronize on a
hidden global object. Alternately:
Object valueLock = new Object;
uint m_value = 42; // The thing to be protected.
uint value() // getter
{
synchronized(valueLock)
return m_value;
}
uint value(uint newbie) // setter
{
synchronized(valueLock)
m_value = newbie;
return newbie;
}
This works if you want to synch only specific functions with respect to
one anohther.
>> 3) use CPU-specific instructions to ensure value access is atomic.
>> This is what Sean has exposed in the Atomic module within Tango. It is
>> a lightweight and low-overhead solution, and works by locking the bus
>> for the duration of the read/write access.
>
> This sounds cool, but I don't quite understand how to use the Atomic
> module - what is msync and which value of it do I pick to make things
> work? I made a post about this in the Tango forum incase it's more
> appropriate to discuss there.
The Tango forums are probably more appropriate, but I can give a quick
summary here (I'm on my way out the door as I write this).
tango.core.Atomic does essentially two things: it ensures that any
operation it performs is atomic, and it provides methods to control
memory ordering regarding such operations. The latter issue is somewhat
complicated, but suffice to say that msync.seq is the safest option and
should be used in most situations. So for the above:
uint m_value = 42;
uint value() // getter
{
return atomicLoad!(msync.seq)( m_value );
}
uint value(uint newbie) // setter
{
atomicStore!(msync.seq)( m_value, newbie );
return newbie;
}
For data which will always be modified atomically, a wrapper struct is
also provided:
Atomic!(uint) m_value;
// Atomic really needs a ctor, but this should work
// for "fast" construction.
m_value.store!(msync.raw)( 42 );
uint value() // getter
{
return m_value.load!(msync.seq);
}
uint value(uint newbie) // setter
{
m_value.store!(msync.seq)( newbie );
return newbie;
}
Please note that Atomic currently only supports x86, but if there's a
demand for it then I may add support for other architectures. If this
happens, it will probably under Posix (and not Win32), since I'm not
entirely sure about out-of-the-box assembler support with DMD/Win32.
> When I was porting Phobos to work on ARM-WinCE, it was very helpful to
> be able to discard a module without breaking other parts of the lib,
> namely in the case of that module requiring a broken language feature or
> inline assembly (inline asm is not currently available with
> arm-wince-pe-gdc, and I don't feel like learning ARM asm yet). That
> said, Atomic looks like it will be very broken on ARM in its current
> state. I also benchmarked synchronized reads vs atomic reads and yeah,
> synchronized was much slower (I picked "whatever makes it compile"
> values for msync). So I'll probably implement a version using only
> synchronization and a version that uses Atomic instead whenever possible.
See above :-) Atomic won't work on ARM without additional code.
By the way, it may also eventually be necessary to add a hardware
instruction for ordering load operations on x86, since I'm becoming
convinced that load reordering is actually allowed by the IA-32 spec
(and it may actually be done on some AMD CPUs). I've been resisting
this until now because it will slow down synchronized loads
substantially for what may be only a small portion of the x86 hardware
in production. So if you (or anyone) decides to use Atomic as-is and
see weird behavior with atomicLoad using msync.acq or msync.hlb, please
let me know.
Sean
More information about the Digitalmars-d-learn
mailing list