digitalmars.D.learn - Obedient threads
- Chris (21/21) Oct 02 2014 What is the best way to kill a thread when it pleases the owner
- thedeemon (6/6) Oct 02 2014 Just use non-blocking receives in main thread's event loop. When
- Chris (4/10) Oct 02 2014 Thanks. I was thinking of something like that, only I haven't
- ketmar via Digitalmars-d-learn (3/6) Oct 02 2014 you can use receiveTimeout! to check if there is some message available.
- Chris (7/12) Oct 02 2014 That won't do. It blocks the main thread too (for the duration of
- ketmar via Digitalmars-d-learn (4/6) Oct 02 2014 don't do hour-long timeouts. 1ms timeout is actually
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (69/80) Oct 02 2014 To add to what ketmar said, even 0.msecs works.
- Chris (5/94) Oct 02 2014 Thanks Ali, you're a legend! I was actually thinking of creating
- ketmar via Digitalmars-d-learn (5/7) Oct 02 2014 it seems that you want thread messaging to be integrated in your event
- Chris (7/18) Oct 03 2014 Exactly. But Ali's solution above might work for my program, if I
What is the best way to kill a thread when it pleases the owner (main thread)? The background is playing audio files. The playback happens in a separate thread so the owner can keep on listening to events triggered by the user (like stop, pause). I have to queue audio files, wait until one has finished, then play the next etc. Communicating between threads does not work with this technique: Owner: // create thread ... ... auto isFinished = receiveOnly!bool(); Thread: // play file ... if (finished) { ownerTid.send(true); } Of course, now Owner waits until it receives the message and is deaf to any user input until Thread has finished, thus there is no way to interrupt the playback. Is there a simple and elegant D way to solve this? Slots are thread local so the observer doesn't know what's going on in another thread, does it?
Oct 02 2014
Just use non-blocking receives in main thread's event loop. When you get a message from child thread that it's finished playing and you decide you don't need that thread anymore, send a message to child "you're dismissed". The child should also have some loop to check for incoming messages non-blockingly. Upon receiving such message it should exit.
Oct 02 2014
On Thursday, 2 October 2014 at 10:33:02 UTC, thedeemon wrote:Just use non-blocking receives in main thread's event loop. When you get a message from child thread that it's finished playing and you decide you don't need that thread anymore, send a message to child "you're dismissed". The child should also have some loop to check for incoming messages non-blockingly. Upon receiving such message it should exit.Thanks. I was thinking of something like that, only I haven't found a way to set up non-blocking receives. What am I missing. I'm sure it's something trivial.
Oct 02 2014
On Thu, 02 Oct 2014 11:36:06 +0000 Chris via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:Thanks. I was thinking of something like that, only I haven't=20 found a way to set up non-blocking receives. What am I missing.=20 I'm sure it's something trivial.you can use receiveTimeout! to check if there is some message available.
Oct 02 2014
On Thursday, 2 October 2014 at 13:05:00 UTC, ketmar via Digitalmars-d-learn wrote:On Thu, 02 Oct 2014 11:36:06 +0000 Chris via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote: you can use receiveTimeout! to check if there is some message available.That won't do. It blocks the main thread too (for the duration of timeout), and it might abandon the thread too early. If you do it like in Ali's example[1], the main thread is blocked in the sense that it does not listen to input. [1] http://ddili.org/ders/d.en/concurrency.html
Oct 02 2014
On Thu, 02 Oct 2014 13:49:33 +0000 Chris via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:That won't do. It blocks the main thread too (for the duration of=20 timeout)don't do hour-long timeouts. 1ms timeout is actually "poll-and-receive". can't see any problems with it.
Oct 02 2014
On 10/02/2014 06:49 AM, Chris wrote:On Thursday, 2 October 2014 at 13:05:00 UTC, ketmar via Digitalmars-d-learn wrote:To add to what ketmar said, even 0.msecs works. In such a case moving the other tasks out of the main thread may be a better option. main can safely block on the message queue while another thread interacts with the outside world. It would be a cleaner event loop that way. I've just improved that example to interact with the user. The worker produces a random message periodically. The user can ask for the most recent message by entering "yes". (I made it so that reading the message also clears it.) import std.stdio; import std.concurrency; import core.thread; import std.string; import std.random; import std.array; void workerFunc(size_t count, Duration duration) { writefln("There will be %s messages every %s.", count, duration); foreach (i; 0 .. count) { Thread.sleep(duration); ownerTid.send(format("message %s: %s", i, uniform(0, 100))); } writeln("workerFunc exiting"); } struct ResultPlease {} void interactor() { bool done = false; while (!done) { write("Would you like to see the result? "); string response = readln.chomp; if (response == "yes") { ownerTid.send(ResultPlease(), thisTid); const result = receiveOnly!string(); if (result.empty) { writeln("Sorry, no result yet."); } else { writefln(`The result is "%s"`, result); } } else { writeln("Ok, no more interaction. Bye."); done = true; } } } void main() { spawnLinked(&workerFunc, 4, 5.seconds); spawnLinked(&interactor); string result; Tid[] completed; while (completed.length < 2) { receive( (string message) { result = message; }, (ResultPlease request, Tid requestor) { requestor.send(result); result = ""; }, (LinkTerminated e) { completed ~= e.tid; } ); } } AliOn Thu, 02 Oct 2014 11:36:06 +0000 Chris via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote: you can use receiveTimeout! to check if there is some message available.That won't do. It blocks the main thread too (for the duration of timeout), and it might abandon the thread too early. If you do it like in Ali's example[1], the main thread is blocked in the sense that it does not listen to input. [1] http://ddili.org/ders/d.en/concurrency.html
Oct 02 2014
On Thursday, 2 October 2014 at 18:08:40 UTC, Ali Çehreli wrote:On 10/02/2014 06:49 AM, Chris wrote:Thanks Ali, you're a legend! I was actually thinking of creating a separate thread as an event listener instead of using main. I'll try that now. Somehow the 1.msecs solution doesn't seem clean enough.On Thursday, 2 October 2014 at 13:05:00 UTC, ketmar via Digitalmars-d-learn wrote:To add to what ketmar said, even 0.msecs works. In such a case moving the other tasks out of the main thread may be a better option. main can safely block on the message queue while another thread interacts with the outside world. It would be a cleaner event loop that way. I've just improved that example to interact with the user. The worker produces a random message periodically. The user can ask for the most recent message by entering "yes". (I made it so that reading the message also clears it.) import std.stdio; import std.concurrency; import core.thread; import std.string; import std.random; import std.array; void workerFunc(size_t count, Duration duration) { writefln("There will be %s messages every %s.", count, duration); foreach (i; 0 .. count) { Thread.sleep(duration); ownerTid.send(format("message %s: %s", i, uniform(0, 100))); } writeln("workerFunc exiting"); } struct ResultPlease {} void interactor() { bool done = false; while (!done) { write("Would you like to see the result? "); string response = readln.chomp; if (response == "yes") { ownerTid.send(ResultPlease(), thisTid); const result = receiveOnly!string(); if (result.empty) { writeln("Sorry, no result yet."); } else { writefln(`The result is "%s"`, result); } } else { writeln("Ok, no more interaction. Bye."); done = true; } } } void main() { spawnLinked(&workerFunc, 4, 5.seconds); spawnLinked(&interactor); string result; Tid[] completed; while (completed.length < 2) { receive( (string message) { result = message; }, (ResultPlease request, Tid requestor) { requestor.send(result); result = ""; }, (LinkTerminated e) { completed ~= e.tid; } ); } } AliOn Thu, 02 Oct 2014 11:36:06 +0000 Chris via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote: you can use receiveTimeout! to check if there is some message available.That won't do. It blocks the main thread too (for the duration of timeout), and it might abandon the thread too early. If you do it like in Ali's example[1], the main thread is blocked in the sense that it does not listen to input. [1] http://ddili.org/ders/d.en/concurrency.html
Oct 02 2014
On Thu, 02 Oct 2014 20:42:49 +0000 Chris via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:I'll try that now. Somehow the 1.msecs solution doesn't seem=20 clean enough.it seems that you want thread messaging to be integrated in your event loop. sorry, there is no easy way to do it now. maybe if libasync will become std.async we will have such feature in phobos out-of-the-box.
Oct 02 2014
On Friday, 3 October 2014 at 04:39:38 UTC, ketmar via Digitalmars-d-learn wrote:On Thu, 02 Oct 2014 20:42:49 +0000 Chris via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:Exactly. But Ali's solution above might work for my program, if I can create a listener thread. The main thread will take care of queuing the audio files and the listener thread checks, if the user has chosen to interrupt the whole thing. The other way around of what I had first in mind.I'll try that now. Somehow the 1.msecs solution doesn't seem clean enough.it seems that you want thread messaging to be integrated in your event loop. sorry, there is no easy way to do it now. maybe if libasync will become std.async we will have such feature in phobos out-of-the-box.
Oct 03 2014