Best replacement for wait/notify (Monitor.Wait()/Monitor.Pulse()) on the CompactFramework?

C

Carl Rosenberger

Hi all,

our system consists of two threads:

(1) Main thread
does all the interaction with user application code

(2) Communication thread
is responsible for client/server communication


Whenever the Main thread (1) needs an instant reply from the server
- thread (1) places a message in the outgoing message queue
- thread (1) starts to wait
- thread (2) sends all outgoing messages to the server
- thread (2) places all available server messages into the
incoming message queue
- thread (2) sends a notify (Monitor.Pulse() to thread (1),
if there are new incoming messages
- thread (1) takes the message from the incoming message
queue and continues it's work.

How would I implement the above in the most efficient way
in CF, without switching to a synchronous mechanism?

Is there an alternative to using Thread#Sleep() and polling?

Thanks in advance for any hints.

Kind regards,
Carl
 
C

Carl Rosenberger

Alex said:
I think you could build this based on AutoResetEvent class

Thanks a lot for the hint, Alex.
To me the class also looks like it could help.
Mutex and ManualResetEvent may work also.

However, since I use my Wait() and Pulse() calls
in the middle of a lock() block, this looks like
I will need to completely implement my own locking
system for CF.

Has anyone done that before?
Any pointers to code?

Really, I think the basic functionality that Java
uses (synchronized, wait, notify) is just about
perfect. I think it should be available on the
CompactFramework as well. Are there any plans to
implement Monitor.Wait() and Monitor.Pulse() on CF?

Kind regards,
Carl
 
C

Carl Rosenberger

Carl said:
However, since I use my Wait() and Pulse() calls
in the middle of a lock() block, this looks like
I will need to completely implement my own locking
system for CF.

That's what I did in the meanwhile.
Below is what I have come up with so far.

Should anyone see a quirk in my approach, I would be
grateful for comments. The code runs O.K. with the
test cases I used but it hasn't been tested
thoroughly yet.

Feel free to use the code for your own Wait()/Pulse()
system on CF.


// Something to be run in the lock block.
// This could be a delegate also.
// We are staying compatible to Java.
public interface Closure4 {
Object run();
}


// This is the trivial default implementation
// to be run on regular .NET, to be used as
// a reference for testing.
using System.Threading;
public class Lock4 {

public Object run(Closure4 closure) {
lock (this) {
return closure.run();
}
}

public void snooze(long timeout) {
Monitor.Wait(this, (int)timeout);
}

public void awake() {
Monitor.Pulse(this);
}
}


// Here ist our CF version. For us it's O.K., if
// the timeout value is ignored.
using System.Threading;

public class Lock4 {

private volatile Thread lockedByThread;

private volatile Thread waitReleased;
private volatile Thread closureReleased;

AutoResetEvent waitEvent = new AutoResetEvent(false);
AutoResetEvent closureEvent = new AutoResetEvent(false);

public Object run(Closure4 closure4) {
enterClosure();
Object ret;
try{
ret = closure4.run();
}catch(Exception e){
awakeClosure();
throw e;
}
awakeClosure();
return ret;
}

public void snooze(long l) {
awakeClosure();
waitWait();
enterClosure();
}

public void awake() {
awakeWait();
}

private void awakeWait() {
lock(this){
waitReleased = Thread.CurrentThread;
waitEvent.Set();
Thread.Sleep(0);
if(waitReleased == Thread.CurrentThread){
waitEvent.Reset();
}
}
}

private void awakeClosure() {
lock(this){
removeLock();
closureReleased = Thread.CurrentThread;
closureEvent.Set();
Thread.Sleep(0);
if(closureReleased == Thread.CurrentThread){
closureEvent.Reset();
}
}
}

private void waitWait(){
waitEvent.WaitOne();
waitReleased = Thread.CurrentThread;
}

private void waitClosure(){
closureEvent.WaitOne();
closureReleased = Thread.CurrentThread;
}

private void enterClosure(){
while(lockedByThread != Thread.CurrentThread){
while(! setLock()){
waitClosure();
}
}
}

private bool setLock(){
lock(this){
if(lockedByThread == null){
lockedByThread = Thread.CurrentThread;
return true;
}
return false;
}
}

private void removeLock(){
lock(this){
if(lockedByThread == Thread.CurrentThread){
lockedByThread = null;
}
}
}
}


Thanks for any hints on how to improve the above.


Kind regards,
Carl
 
C

Carl Rosenberger

Carl said:
Below is what I have come up with so far.

The code that I posted turned out to work O.K.

However, with the poor threading performance of
the CF devices that we tested on, we came to
the conclusion that a synchronous communication
implementation with a single thread that does
all the work, is a better idea. That's what
we did and everything runs O.K. now. A BETA
of our object database engine for .NET and CF
will soon be available on our website.

An observation when you run two VS.NET instances
on one machine, one with our database server, one
with our client running in the emulator:
The thread scheduling on W2K with this setup is
dreadful. It practically doesn't work out. A "real"
decent PocketPC device (iPAQ 5xxx) on USB works
a lot better to test client/server networking
tasks.

Thanks again for your excellent hint to use
AutoResetEvent Alex.

Kind regards,
Carl
 
A

Alex Feinman [MVP]

Carl Rosenberger said:
Carl Rosenberger wrote:
An observation when you run two VS.NET instances
on one machine, one with our database server, one
with our client running in the emulator:
The thread scheduling on W2K with this setup is
dreadful. It practically doesn't work out. A "real"
decent PocketPC device (iPAQ 5xxx) on USB works
a lot better to test client/server networking
tasks.

The emulator is a version of Connectix Virtual PC and as such is a
performance hit by itself. There is now way to debug time-critical or
CPU-intensive code on the emulator, even on the fast boxes. The only way to
go is a USB-Connected or (W)LAN-connected device
Thanks again for your excellent hint to use
AutoResetEvent Alex.

You are welcome
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Monitor.Pulse question 2
Monitor.Pulse Methos 2
Monitor.Wait, with timeout 2
Inter-thread message queue in C# 6
UDP Server scalability question 2
Dispatcher Threads 1
MSMQ on Win CE 4.1 3
Threading in .Net... 4

Top