mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-04-05 03:19:03 +02:00
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
This commit is contained in:
138
tango/example/synchronization/barrier.d
Normal file
138
tango/example/synchronization/barrier.d
Normal file
@@ -0,0 +1,138 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.Barrier;
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.io.Stdout;
|
||||
private import tango.text.convert.Integer;
|
||||
debug (barrier)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.Barrier module.
|
||||
*/
|
||||
void main(char[][] args)
|
||||
{
|
||||
const uint MaxThreadCount = 100;
|
||||
const uint LoopsPerThread = 10000;
|
||||
|
||||
debug (barrier)
|
||||
{
|
||||
Logger log = Log.getLogger("barrier");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Barrier test");
|
||||
}
|
||||
|
||||
Barrier barrier = new Barrier(MaxThreadCount);
|
||||
Mutex mutex = new Mutex();
|
||||
uint count = 0;
|
||||
uint correctCount = 0;
|
||||
|
||||
void barrierTestThread()
|
||||
{
|
||||
debug (barrier)
|
||||
{
|
||||
Logger log = Log.getLogger("barrier." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
for (uint i; i < LoopsPerThread; ++i)
|
||||
{
|
||||
// 'count' is a resource shared by multiple threads, so we must
|
||||
// acquire the mutex before modifying it.
|
||||
synchronized (mutex)
|
||||
{
|
||||
// debug (barrier)
|
||||
// log.trace("Acquired mutex");
|
||||
count++;
|
||||
// debug (barrier)
|
||||
// log.trace("Releasing mutex");
|
||||
}
|
||||
}
|
||||
|
||||
// We wait for all the threads to finish counting.
|
||||
debug (barrier)
|
||||
log.trace("Waiting on barrier");
|
||||
barrier.wait();
|
||||
debug (barrier)
|
||||
log.trace("Barrier was opened");
|
||||
|
||||
// We make sure that all the threads exited the barrier after
|
||||
// *all* of them had finished counting.
|
||||
synchronized (mutex)
|
||||
{
|
||||
// debug (barrier)
|
||||
// log.trace("Acquired mutex");
|
||||
if (count == MaxThreadCount * LoopsPerThread)
|
||||
{
|
||||
++correctCount;
|
||||
}
|
||||
// debug (barrier)
|
||||
// log.trace("Releasing mutex");
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in Barrier test thread {0}:\n{1}\n",
|
||||
Thread.getThis().name, e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in Barrier test thread {0}:\n{1}\n",
|
||||
Thread.getThis().name, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; ++i)
|
||||
{
|
||||
thread = new Thread(&barrierTestThread);
|
||||
thread.name = "thread-" ~ format(tmp, i);
|
||||
|
||||
group.add(thread);
|
||||
debug (barrier)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
debug (barrier)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (count == MaxThreadCount * LoopsPerThread)
|
||||
{
|
||||
debug (barrier)
|
||||
log.info("The Barrier test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (barrier)
|
||||
{
|
||||
log.error("The Barrier is not working properly: the counter has an incorrect value");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The Barrier is not working properly: the counter has an incorrect value");
|
||||
}
|
||||
}
|
||||
}
|
||||
307
tango/example/synchronization/condition.d
Normal file
307
tango/example/synchronization/condition.d
Normal file
@@ -0,0 +1,307 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.Condition;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.text.convert.Integer;
|
||||
private import tango.io.Stdout;
|
||||
debug (condition)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
void main(char[][] args)
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Condition test");
|
||||
}
|
||||
|
||||
testNotifyOne();
|
||||
testNotifyAll();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test for Condition.notify().
|
||||
*/
|
||||
void testNotifyOne()
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-one");
|
||||
}
|
||||
|
||||
scope Mutex mutex = new Mutex();
|
||||
scope Condition cond = new Condition(mutex);
|
||||
int waiting = 0;
|
||||
Thread thread;
|
||||
|
||||
void notifyOneTestThread()
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-one." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
scope(exit)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
waiting++;
|
||||
|
||||
while (waiting != 2)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Waiting on condition variable");
|
||||
cond.wait();
|
||||
}
|
||||
|
||||
debug (condition)
|
||||
log.trace("Condition variable was signaled");
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
debug (condition)
|
||||
log.trace("Exiting thread");
|
||||
}
|
||||
|
||||
thread = new Thread(¬ifyOneTestThread);
|
||||
thread.name = "thread-1";
|
||||
|
||||
debug (condition)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
try
|
||||
{
|
||||
// Poor man's barrier: wait until the other thread is waiting.
|
||||
while (true)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (waiting != 1)
|
||||
{
|
||||
Thread.yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
waiting++;
|
||||
|
||||
debug (condition)
|
||||
log.trace("Notifying test thread");
|
||||
cond.notify();
|
||||
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
thread.join();
|
||||
|
||||
if (waiting == 2)
|
||||
{
|
||||
debug (condition)
|
||||
log.info("The Condition notification test to one thread was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
log.error("The condition variable notification to one thread is not working");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The condition variable notification to one thread is not working");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in main thread:\n{0}", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test for Condition.notifyAll().
|
||||
*/
|
||||
void testNotifyAll()
|
||||
{
|
||||
const uint MaxThreadCount = 10;
|
||||
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-all");
|
||||
}
|
||||
|
||||
scope Mutex mutex = new Mutex();
|
||||
scope Condition cond = new Condition(mutex);
|
||||
int waiting = 0;
|
||||
|
||||
/**
|
||||
* This thread waits for a notification from the main thread.
|
||||
*/
|
||||
void notifyAllTestThread()
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-all." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
waiting++;
|
||||
|
||||
while (waiting != MaxThreadCount + 1)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Waiting on condition variable");
|
||||
cond.wait();
|
||||
}
|
||||
|
||||
debug (condition)
|
||||
log.trace("Condition variable was signaled");
|
||||
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
debug (condition)
|
||||
log.trace("Exiting thread");
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; ++i)
|
||||
{
|
||||
thread = new Thread(¬ifyAllTestThread);
|
||||
thread.name = "thread-" ~ format(tmp, i);
|
||||
|
||||
group.add(thread);
|
||||
debug (condition)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Poor man's barrier: wait until all the threads are waiting.
|
||||
while (true)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (waiting != MaxThreadCount)
|
||||
{
|
||||
Thread.yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
waiting++;
|
||||
|
||||
debug (condition)
|
||||
log.trace("Notifying all threads");
|
||||
cond.notifyAll();
|
||||
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
debug (condition)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (waiting == MaxThreadCount + 1)
|
||||
{
|
||||
debug (condition)
|
||||
log.info("The Condition notification test to many threads was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
log.error("The condition variable notification to many threads is not working");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The condition variable notification to many threads is not working");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in main thread:\n{0}", e.toString());
|
||||
}
|
||||
}
|
||||
248
tango/example/synchronization/mutex.d
Normal file
248
tango/example/synchronization/mutex.d
Normal file
@@ -0,0 +1,248 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.io.Stdout;
|
||||
private import tango.text.convert.Integer;
|
||||
debug (mutex)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.Mutex module.
|
||||
*/
|
||||
void main(char[][] args)
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Mutex test");
|
||||
}
|
||||
|
||||
testNonRecursive();
|
||||
testLocking();
|
||||
testRecursive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that non-recursive mutexes actually do what they're supposed to do.
|
||||
*
|
||||
* Remarks:
|
||||
* Windows only supports recursive mutexes.
|
||||
*/
|
||||
void testNonRecursive()
|
||||
{
|
||||
version (Posix)
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex.non-recursive");
|
||||
}
|
||||
|
||||
Mutex mutex = new Mutex(Mutex.Type.NonRecursive);
|
||||
bool couldLock;
|
||||
|
||||
try
|
||||
{
|
||||
mutex.lock();
|
||||
debug (mutex)
|
||||
log.trace("Acquired mutex");
|
||||
couldLock = mutex.tryLock();
|
||||
if (couldLock)
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.trace("Re-acquired mutex");
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
log.trace("Re-acquiring the mutex failed");
|
||||
}
|
||||
debug (mutex)
|
||||
log.trace("Releasing mutex");
|
||||
mutex.unlock();
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught when testing non-recursive mutexes:\n{0}\n", e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught when testing non-recursive mutexes:\n{0}\n", e.toString());
|
||||
}
|
||||
|
||||
if (!couldLock)
|
||||
{
|
||||
debug (mutex)
|
||||
log.info("The non-recursive Mutex test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.error("Non-recursive mutexes are not working: "
|
||||
"Mutex.tryAcquire() did not fail on an already acquired mutex");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "Non-recursive mutexes are not working: "
|
||||
"Mutex.tryAcquire() did not fail on an already acquired mutex");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create several threads that acquire and release a mutex several times.
|
||||
*/
|
||||
void testLocking()
|
||||
{
|
||||
const uint MaxThreadCount = 10;
|
||||
const uint LoopsPerThread = 1000;
|
||||
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex.locking");
|
||||
}
|
||||
|
||||
Mutex mutex = new Mutex();
|
||||
uint lockCount = 0;
|
||||
|
||||
void mutexLockingThread()
|
||||
{
|
||||
try
|
||||
{
|
||||
for (uint i; i < LoopsPerThread; i++)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
lockCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught inside mutex testing thread:\n{0}\n", e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught inside mutex testing thread:\n{0}\n", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; i++)
|
||||
{
|
||||
thread = new Thread(&mutexLockingThread);
|
||||
thread.name = "thread-" ~ format(tmp, i);
|
||||
|
||||
debug (mutex)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
group.add(thread);
|
||||
}
|
||||
|
||||
debug (mutex)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (lockCount == MaxThreadCount * LoopsPerThread)
|
||||
{
|
||||
debug (mutex)
|
||||
log.info("The Mutex locking test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.error("Mutex locking is not working properly: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false,"Mutex locking is not working properly: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that recursive mutexes actually do what they're supposed to do.
|
||||
*/
|
||||
void testRecursive()
|
||||
{
|
||||
const uint LoopsPerThread = 1000;
|
||||
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex.recursive");
|
||||
}
|
||||
|
||||
Mutex mutex = new Mutex;
|
||||
uint lockCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
for (uint i = 0; i < LoopsPerThread; i++)
|
||||
{
|
||||
mutex.lock();
|
||||
lockCount++;
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in recursive mutex test:\n{0}\n", e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in recursive mutex test:\n{0}\n", e.toString());
|
||||
}
|
||||
|
||||
for (uint i = 0; i < lockCount; i++)
|
||||
{
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
if (lockCount == LoopsPerThread)
|
||||
{
|
||||
debug (mutex)
|
||||
log.info("The recursive Mutex test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.error("Recursive mutexes are not working: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "Recursive mutexes are not working: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
}
|
||||
}
|
||||
}
|
||||
145
tango/example/synchronization/readwritemutex.d
Normal file
145
tango/example/synchronization/readwritemutex.d
Normal file
@@ -0,0 +1,145 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.ReadWriteMutex;
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Thread;
|
||||
private import tango.text.convert.Integer;
|
||||
debug (readwritemutex)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.ReadWriteMutex module.
|
||||
*/
|
||||
void main(char[][] args)
|
||||
{
|
||||
const uint ReaderThreads = 100;
|
||||
const uint WriterThreads = 20;
|
||||
const uint LoopsPerReader = 10000;
|
||||
const uint LoopsPerWriter = 1000;
|
||||
const uint CounterIncrement = 3;
|
||||
|
||||
debug (readwritemutex)
|
||||
{
|
||||
Logger log = Log.getLogger("readwritemutex");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("ReadWriteMutex test");
|
||||
}
|
||||
|
||||
ReadWriteMutex rwlock = new ReadWriteMutex();
|
||||
Mutex mutex = new Mutex();
|
||||
uint readCount = 0;
|
||||
uint passed = 0;
|
||||
uint failed = 0;
|
||||
|
||||
void mutexReaderThread()
|
||||
{
|
||||
debug (readwritemutex)
|
||||
{
|
||||
Logger log = Log.getLogger("readwritemutex." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting reader thread");
|
||||
}
|
||||
|
||||
for (uint i = 0; i < LoopsPerReader; ++i)
|
||||
{
|
||||
// All the reader threads acquire the mutex for reading and when they are
|
||||
// all done
|
||||
synchronized (rwlock.reader)
|
||||
{
|
||||
for (uint j = 0; j < CounterIncrement; ++j)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
++readCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mutexWriterThread()
|
||||
{
|
||||
debug (readwritemutex)
|
||||
{
|
||||
Logger log = Log.getLogger("readwritemutex." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting writer thread");
|
||||
}
|
||||
|
||||
for (uint i = 0; i < LoopsPerWriter; ++i)
|
||||
{
|
||||
synchronized (rwlock.writer)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (readCount % 3 == 0)
|
||||
{
|
||||
++passed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < ReaderThreads; ++i)
|
||||
{
|
||||
thread = new Thread(&mutexReaderThread);
|
||||
thread.name = "reader-" ~ format(tmp, i);
|
||||
|
||||
debug (readwritemutex)
|
||||
log.trace("Created reader thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
group.add(thread);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < WriterThreads; ++i)
|
||||
{
|
||||
thread = new Thread(&mutexWriterThread);
|
||||
thread.name = "writer-" ~ format(tmp, i);
|
||||
|
||||
debug (readwritemutex)
|
||||
log.trace("Created writer thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
group.add(thread);
|
||||
}
|
||||
|
||||
debug (readwritemutex)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (passed == WriterThreads * LoopsPerWriter)
|
||||
{
|
||||
debug (readwritemutex)
|
||||
log.info("The ReadWriteMutex test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (readwritemutex)
|
||||
{
|
||||
log.error("The ReadWriteMutex is not working properly: the counter has an incorrect value");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The ReadWriteMutex is not working properly: the counter has an incorrect value");
|
||||
}
|
||||
}
|
||||
}
|
||||
340
tango/example/synchronization/semaphore.d
Normal file
340
tango/example/synchronization/semaphore.d
Normal file
@@ -0,0 +1,340 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2007 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
module semaphore;
|
||||
|
||||
private import tango.core.sync.Semaphore;
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.io.Console;
|
||||
private import tango.text.stream.LineIterator;
|
||||
private import tango.text.convert.Integer;
|
||||
private import tango.sys.Process;
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
const char[] SemaphoreName = "TestProcessSemaphore";
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.Barrier module.
|
||||
*/
|
||||
int main(char[][] args)
|
||||
{
|
||||
if (args.length == 1)
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Semaphore test");
|
||||
}
|
||||
|
||||
testSemaphore();
|
||||
testProcessSemaphore(args[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return testSecondProcessSemaphore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for single-process (multi-threaded) semaphores.
|
||||
*/
|
||||
void testSemaphore()
|
||||
{
|
||||
const uint MaxThreadCount = 10;
|
||||
|
||||
// Semaphore used in the tests. Start it "locked" (i.e., its initial
|
||||
// count is 0).
|
||||
Semaphore sem = new Semaphore(MaxThreadCount - 1);
|
||||
Mutex mutex = new Mutex();
|
||||
uint count = 0;
|
||||
bool passed = false;
|
||||
|
||||
void semaphoreTestThread()
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore.single." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
uint threadNumber;
|
||||
|
||||
// 'count' is a resource shared by multiple threads, so we must
|
||||
// acquire the mutex before modifying it.
|
||||
synchronized (mutex)
|
||||
{
|
||||
// debug (semaphore)
|
||||
// log.trace("Acquired mutex");
|
||||
threadNumber = ++count;
|
||||
// debug (semaphore)
|
||||
// log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
// We wait for all the threads to finish counting.
|
||||
if (threadNumber < MaxThreadCount)
|
||||
{
|
||||
sem.wait();
|
||||
debug (semaphore)
|
||||
log.trace("Acquired semaphore");
|
||||
|
||||
while (true)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (count >= MaxThreadCount + 1)
|
||||
break;
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Releasing semaphore");
|
||||
sem.notify();
|
||||
}
|
||||
else
|
||||
{
|
||||
passed = !sem.tryWait();
|
||||
if (passed)
|
||||
{
|
||||
debug (semaphore)
|
||||
log.trace("Tried to acquire the semaphore too many times and failed: OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
log.error("Tried to acquire the semaphore too may times and succeeded: FAILED");
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Releasing semaphore");
|
||||
sem.notify();
|
||||
}
|
||||
synchronized (mutex)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Cerr("Sync exception caught in Semaphore test thread " ~ Thread.getThis().name ~
|
||||
":\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Cerr("Unexpected exception caught in Semaphore test thread " ~ Thread.getThis().name ~
|
||||
":\n" ~ e.toString()).newline;
|
||||
}
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore.single");
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; ++i)
|
||||
{
|
||||
thread = new Thread(&semaphoreTestThread);
|
||||
thread.name = "thread-" ~ tango.text.convert.Integer.format(tmp, i);
|
||||
|
||||
group.add(thread);
|
||||
debug (semaphore)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (passed)
|
||||
{
|
||||
debug (semaphore)
|
||||
log.info("The Semaphore test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
log.error("The Semaphore is not working properly: it allowed "
|
||||
"to be acquired more than it should have done");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The Semaphore is not working properly: it allowed "
|
||||
"to be acquired more than it should have done");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for multi-process semaphores: this test works by creating a copy of
|
||||
* this process that tries to acquire the ProcessSemaphore that was created
|
||||
* in this function. If everything works as expected, the attempt should fail,
|
||||
* as the count of the semaphore is set to 1.
|
||||
*/
|
||||
void testProcessSemaphore(char[] programName)
|
||||
{
|
||||
/+
|
||||
bool success = false;
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore.multi");
|
||||
Logger childLog = Log.getLogger("semaphore.multi.child");
|
||||
|
||||
log.info("ProcessSemaphore test");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
scope ProcessSemaphore sem = new ProcessSemaphore(SemaphoreName, 1);
|
||||
Process proc = new Process(programName, "2");
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Created ProcessSemaphore('" ~ SemaphoreName ~ "')'");
|
||||
|
||||
sem.wait();
|
||||
debug (semaphore)
|
||||
log.trace("Acquired semaphore in main process");
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Executing child test process: " ~ proc.toString());
|
||||
proc.execute();
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
foreach (line; new LineIterator!(char)(proc.stdout))
|
||||
{
|
||||
childLog.trace(line);
|
||||
}
|
||||
}
|
||||
foreach (line; new LineIterator!(char)(proc.stderr))
|
||||
{
|
||||
Cerr(line).newline;
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Waiting for child process to finish");
|
||||
auto result = proc.wait();
|
||||
|
||||
success = (result.reason == Process.Result.Exit && result.status == 2);
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Releasing semaphore in main process");
|
||||
sem.notify();
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Cerr("Sync exception caught in ProcessSemaphore main test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (ProcessException e)
|
||||
{
|
||||
Cerr("Process exception caught in ProcessSemaphore main test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Cerr("Unexpected exception caught in ProcessSemaphore main test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
debug (semaphore)
|
||||
log.info("The ProcessSemaphore test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
log.error("The multi-process semaphore is not working");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The multi-process semaphore is not working");
|
||||
}
|
||||
}
|
||||
+/
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for multi-process semaphores (second process).
|
||||
*/
|
||||
int testSecondProcessSemaphore()
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/+
|
||||
debug (semaphore)
|
||||
{
|
||||
Cout("Starting child process\n");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
scope ProcessSemaphore sem = new ProcessSemaphore(SemaphoreName);
|
||||
bool success;
|
||||
|
||||
success = !sem.tryAcquire();
|
||||
if (success)
|
||||
{
|
||||
debug (semaphore)
|
||||
Cout("Tried to acquire semaphore in child process and failed: OK\n");
|
||||
rc = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
Cout("Acquired semaphore in child process: this should not have happened\n");
|
||||
Cout("Releasing semaphore in child process\n");
|
||||
}
|
||||
sem.notify();
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Cerr("Sync exception caught in ProcessSemaphore child test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (ProcessException e)
|
||||
{
|
||||
Cerr("Process exception caught in ProcessSemaphore child test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Cerr("Unexpected exception caught in ProcessSemaphore child test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
Cout("Leaving child process\n");
|
||||
|
||||
+/
|
||||
return rc;
|
||||
}
|
||||
Reference in New Issue
Block a user