January 13, 2010 [dmd-concurrency] Sending mesages to non-listening threads | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Wed, 13 Jan 2010 13:49:49 -0500, Andrei Alexandrescu <andrei at erdani.com> wrote:
> Robert Jacques wrote:
>> Erlang uses "passers" all the time. The difference is spinning off an Erlang process is no big deal, so you don't think about it. Spinning off an OS thread, on the other hand, is a big deal.
>
> Point taken. BTW we should reserve the possibility to implement abstract threads in D as well. I wonder how Erlang achieves its good performance numbers.
A key thing to remember is that Erlang's runtime is actually serial: on multi-core machines it simply spawns multiple processes. This is a great and efficient paradigm, (It makes the GC thread-local, etc) but it's somewhat all or none. There are lot's of issues with mixing fibers and threads without operating system support. I know it's broken pre-Vista on Windows, because certain OS calls make some poor assumptions, resulting is rare hard to track down bugs. I also know this effect third party libraries do this too (OpenGL drivers, etc.). I don't know if the *nix world has any hidden gotchas like that. I think message passing should cleanly support D fibers, and we should encourage their usage: programming with threads doesn't scale since inevitably you either have too many or not enough.
One way to mitigate this is to have a task library like cilk or Intel's Threading Building blocks.
|
January 13, 2010 [dmd-concurrency] Sending mesages to non-listening threads | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques | Le 2010-01-13 ? 14:58, Robert Jacques a ?crit : > [...] programming with threads doesn't scale since inevitably you either have too many or not enough. > > One way to mitigate this is to have a task library like cilk or Intel's Threading Building blocks. Mac OS X since 10.6 also offers libdispatch where the kernel itself can help processes decide when to create new threads. The project is opensource and it looks like it might be adopted by FreeBSD too. <http://libdispatch.macosforge.org/> The API is very nice to use with blocks (Apple extension to C). Here is a multithreaded foreach creating tasks executed by libdispatch: dispatch_apply(count, queue, ^(size_t i) { printf("%u\n",i); }); Can we do something like this in D, given all the sharing protections? -- Michel Fortin michel.fortin at michelf.com http://michelf.com/ |
January 13, 2010 [dmd-concurrency] Sending mesages to non-listening threads | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | 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.
I've gone back and analyzed the GPU functions from my research. I've
found that all (save one) could be specified as a map or reduce of a
const delegate. The one exception involved a scatter write which use
used the algorithm's logic + some barriers to prevent races.
Note that D doesn't have shared/immutable/pure/const delegates today.
If you take the address of a member function or a shared member
function you get the same result.
Sent from my iPod
On 2010-01-13, at 4:05 PM, Michel Fortin <michel.fortin at michelf.com> wrote:
> Le 2010-01-13 ? 14:58, Robert Jacques a ?crit :
>
>> [...] programming with threads doesn't scale since inevitably you either have too many or not enough.
>>
>> One way to mitigate this is to have a task library like cilk or Intel's Threading Building blocks.
>
> Mac OS X since 10.6 also offers libdispatch where the kernel itself can help processes decide when to create new threads. The project is opensource and it looks like it might be adopted by FreeBSD too.
>
> <http://libdispatch.macosforge.org/>
>
> The API is very nice to use with blocks (Apple extension to C). Here is a multithreaded foreach creating tasks executed by libdispatch:
>
> dispatch_apply(count, queue, ^(size_t i) {
> printf("%u\n",i);
> });
>
> Can we do something like this in D, given all the sharing protections?
>
>
> --
> Michel Fortin
> michel.fortin at michelf.com
> http://michelf.com/
>
>
>
> _______________________________________________
> dmd-concurrency mailing list
> dmd-concurrency at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-concurrency
|
January 13, 2010 [dmd-concurrency] Sending mesages to non-listening threads | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Le 2010-01-13 ? 13:57, Sean Kelly a ?crit : >> GUI frameworks already have their own message passing system (for events), and their own event loops. Could there be a way to attach a customized "passer" function which would make the sending thread pass messages in a special way? This could allow messages to be sent to GUI threads by wrapping them in a GUI event. It'd simplify things from the worker thread point of view, which wouldn't have to mess with GUI stuff. > > For GUI events, it's more likely that you'd have a thread waiting for those messages and then repackaging and resending them using the D model. I was speaking of the reverse: sending D messages to a GUI thread having its own event loop (for instance after some work is done): // Executed in GUI thread void onClick() { spawn(&doWork, "work done"); } void onMessage(string message) { if (message == "work done") { /* do something */ } } // Executed in worker thread void doWork(string doneMessage) { // working here. send(mainTid, doneMessage); } The idea is to not have to write GUI-specific code in doWork. -- Michel Fortin michel.fortin at michelf.com http://michelf.com/ |
January 13, 2010 [dmd-concurrency] Sending mesages to non-listening threads | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques | 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/ |
Copyright © 1999-2021 by the D Language Foundation