Bug 14953 – std.concurrency: Add function to flush message box

Status
NEW
Severity
enhancement
Priority
P4
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2015-08-24T09:35:37Z
Last change time
2024-12-01T16:24:57Z
Assigned to
No Owner
Creator
Chris
Moved to GitHub: phobos#10139 →

Comments

Comment #0 by wendlec — 2015-08-24T09:35:37Z
This enhancement request was inspired by this thread: http://forum.dlang.org/post/[email protected] The scenario: A thread has several items in the message box, and the user wants to cancel not just the current operation but flush the thread's message box, since the items in the message box are no longer relevant. The current behavior is that the thread insists on processing all items in the message box. To suppress the thread from doing actual work, John Colvin proposed this workaround: void flushMailbox() { bool r; do { r = receiveTimeout(Duration.zero, (Variant _){}); } while(r); } In this way, the thread loops over each item in the message box, but does nothing - until the message box is empty. However, it would be more efficient to have a library function that empties the message box immediately, instead of looping over the message box, cancelling each item individually, before new input can be processed.
Comment #1 by sean — 2015-08-25T20:51:45Z
I think this can be handled a few different ways. The most straightforward would be to do: m_localBox.clear(); m_localPty.clear(); Which would wipe everything. It might be better (albeit slower) to let the user supply a filter though. Basically: discard(int,int,int); Removes all messages that would map to: receive((int, int, int) {}); And: discard(Variant); Would effectively clear the mailbox. Perhaps this second version could special case to the efficient: m_localBox.clear(); m_localPty.clear(); mentioned above.
Comment #2 by sean — 2015-08-25T20:57:17Z
That said, it seems like the underlying problem here may be dataflow-related. How do you know that all pending messages are really no longer relevant? If messages are really backing up (ie. something is producing more than you can consume), maybe the dataflow is incorrect. More consumers are needed, or maybe some sort of throttling mechanism. My concern is that I'm not sure that messages should ever be just discarded in bulk. I'd love to hear a good example where they should. So while the API seems straightforward, I'm not entirely convinced that it should exist. Thoughts?
Comment #3 by wendlec — 2015-08-26T09:12:35Z
I understand your concerns regarding data flow. However, it's up to the user (programmer) to determine whether or not the pending messages are relevant. A use case: a text-to-speech synthesizer that has several sentences in the queue (e.g. reading out a document's content sentence by sentence or spelling out a word letter by letter). When the user presses a button to cancel the speech, the remaining items in the queue that haven't been spoken yet should be flushed immediately, which is the desired behavior, else the user would have pressed "pause". I'm sure there are other use cases. If the API is flexible enough to offer a mechanism for both an immediate and a selective (filtered) flush, as you suggested, I think we're on the safe side. We should definitely have a method with a filter too.
Comment #4 by wendlec — 2015-08-27T09:24:56Z
Related to this is the possibility to get the size of the message box, e.g. you would only want to flush a message box, if its size is > 0. I haven't found a way to get the size of the message box, unless something has escaped me. I could open a new ticket for this. Thoughts?
Comment #5 by dmitry.olsh — 2015-08-27T13:28:23Z
> Related to this is the possibility to get the size of the message box, e.g. you would only want to flush a message box, if its size is > 0. I haven't found a way to get the size of the message box, unless something has escaped me. In an async world with fire and forget message passing all of the above is marred with race conditions. You might check that size == 0 the next instant the message comes in. I think the only legitimate use case would be dropUntil!(SomeMessageTypesHere) as it at least has a point of serialization - marker message in a stream of messages.
Comment #6 by wendlec — 2015-08-27T13:54:27Z
You assume a scenario where the programmer has no control over the data flow and messages can come from anywhere in at random, which is not necessarily the case. If threads follow a message passing protocol there is naturally some sort of synchronization between the threads.
Comment #7 by sean — 2015-08-27T17:33:45Z
I think there's already a bugzilla for getting the mailbox size. It's definitely come up before, and would be a trivial change. The way the MessageBox code works is it has a thread-local queue and then a shared queue. When a match isn't found in the thread-local queue the shared queue is moved to the local queue and the match continues on the new messages. All of these operations (empty queue, get size, etc) would operate on the local queue only. Touching the shared queue in any way requires acquiring a mutex, which is generally not what you want for these operations. In essence, messages in the shared queue are messages that "arrived" after your operation was executed.
Comment #8 by wendlec — 2015-08-28T11:02:57Z
That's perfectly all right. It should be thread local, because it only concerns the thread in question. But the programmer should have control over any local thread. At the moment it's a bit like as if a thread was a higher being and had a life of its own and you're not meant to interfere with it. However, threads are part of a program's logic and programmers should be able to control them just as they control the main thread.
Comment #9 by sean — 2015-08-28T17:02:29Z
In general I agree. However, one key feature of std.concurrency is that it can use different Schedulers to achieve different performance requirements. So general actor code should never simply assume it's being run in a dedicated kernel thread or whatever. But as this is a systems language, if you explicitly specify the Scheduler at initialization time, then code written specifically for that application can exploit this knowledge and call the low-level core.thread routines as needed. The assumption being that if you specify the Scheduler then you Know What You're Doing and accept any consequences for mistakes.
Comment #10 by wendlec — 2015-08-31T09:11:28Z
I see. It still may be necessary to know the size of the message box and be able to flush it. The fact that messages stick around for the life span of the thread can lead to undesired behavior, especially when the thread is meant to be running in the background for the duration of the program. You may close a thread down, once you're no longer interested in the message box, and start a new one for the next input, but that seems rather wasteful and may block the main thread while it is waiting for the closing down protocol to finish. I can imagine that this may be an issue for computer games. If there is a good solution other than introducing a new method to flush the message box, I'd be happy, but so far I haven't found it.
Comment #11 by robert.schadek — 2024-12-01T16:24:57Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/phobos/issues/10139 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB