[dmd-concurrency] Sending mesages to non-listening threads
Michel Fortin
michel.fortin at michelf.com
Wed Jan 13 15:30:16 PST 2010
Le 2010-01-13 à 16:30, Robert Jacques a écrit :
> I've been thinking about this. Obviously, a shared delegate is perfectly safe. (pure or immutable delegates are also safe) But, there are some obvious performance/use issues.
With an event handling system in a thread, you could make a special kind of asynchronous delegate that would always execute in its thread of origin. You can do this easily with Cocoa (performSelector:inThread:), but there are obviously no safeties for race conditions.
Here's what I'm thinking it could look in D: have a template struct -- lets call it AsyncCall -- with an opCall operator that simply send back a message to the originator thread with a delegate (valid in that thread) and the arguments (from the calling thread). Could be used like this:
void main() {
bool done = false;
void setDone(bool value) {
done = value;
}
// create worker, give it a callback to call when it has finished
Tid tid = spawn(&worker, AsyncCall!(bool)(&setDone));
// this is some sort of event-halding loop that accepts asynchronous calls.
while (!done) {
receive((AsyncCall!(bool) callback, bool arg) { callback(arg) });
}
}
void worker(AsyncCall!(bool) setDone) {
/* do something */
setDone(true);
}
The struct enforce thread-safety by making sure a call is always sent to the thread from which the delegate was taken. It simply contains a tid and a delegate.
immutable struct AsyncCall!(A...) {
private Tid tid;
private void delegate(A) callee;
this(void delegate(A) callee) {
this.tid = thisTid;
this.callee = callee;
}
void opCall(A args) {
if (tid == thisTid)
callee(args);
else
tid.send(callee, args);
}
}
Obviously, that's only for asynchronous calls, there's no way to return a value from a MessageCall. Also, it will only work for thread-to-thread communications.
Improving my previous example of simple GUI programming, with AsyncCall you could do this (assuming the GUI event loop automatically execute the async calls it receives):
// Executed in GUI thread
void onClick() {
StatusWindow statusWindow = new StatusWindow("Working hard...");
spawn(&doWork, asyncCall((float fractionDone) {
statusWindow.completion = fractionDone;
}), asyncCall({
statusWindow.close();
});
}
// Executed in worker thread
void doWork(AsyncCall!(float) updateStatus, AsyncCall!() callWhenDone) {
sleep(2); // working here.
updateStatus(0.33);
sleep(2); // working here.
updateStatus(0.66);
sleep(2); // working here.
updateStatus(1.00);
callWhenDone();
}
--
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/
More information about the dmd-concurrency
mailing list