January 21, 2010 [dmd-concurrency] Shutdown protocol | |
|---|---|
Posted in reply to Andrei Alexandrescu | On Thu, Jan 21, 2010 at 1:41 AM, Andrei Alexandrescu <andrei at erdani.com>wrote: > Sean Kelly wrote: > >> On Jan 20, 2010, at 3:54 PM, Andrei Alexandrescu wrote: >> >> Sean Kelly wrote: >>> >>>> On Jan 20, 2010, at 11:26 AM, Andrei Alexandrescu wrote: >>>> >>>>> I don't think so. When the two instances of the copy threads finish >>>>> reading and sending messages to their writers, they return. As a >>>>> consequence, wait returns. As a consequence, main finishes. >>>>> >>>>> At this critical point, we have the following situation: >>>>> >>>>> (a) main has finished, therefore the shutdown mode is in effect >>>>> >>>>> (b) There are a number of messages in flight containing buffers waiting >>>>> to be written in the two files. >>>>> >>>>> The important thing to do is to NOT throw shutdown as long as calls to >>>>> receive() would not block. >>>>> >>>> That sounds like a horrible race problem. >>>> >>> >>> Not at all. On the contrary, it's the stark opposite of a race: >>> >>> * Readers only finish after they have sent all messages they had to send. >>> >>> * Application doesn't shutdown until all sent messages have been acted >>> upon. >>> >> >> If the reader is slower than the writer it's entirely possible that the >> writer will block on receive() during processing. The receiver really only >> knows that it's done when it receives a message to that effect from the >> reader thread. If the threads were linked then this might be a "normal" >> shutdown message, for example. Funny now that we're talking about this how >> many use cases I'm thinking of for bidirectional linking. >> > > I don't think so. Say the reader is moving at 1 byte/millenium and the > writer is moving at 1 petabyte/femtosecond. So the writer will spend > virtually all of its time blocked in receive(). > > At the point the reader is finishing, the following actions happen in > causal order: > > 1. The reader sends the last data message to the writer > > 2. The reader's function returns to main > > 3. main returns > > Regardless of the relative speeds of the reader and the writer, causality > above stays the same. There can be no race. > > > Andrei > Assuming one reader. What about a scenario where there are several each of readers and writers, maybe the data flow of 'diff' as a simple example? In this case we should assume that main knows the tids of all the readers rather than running them directly as in the two thread file copy example. More generally, for any set of queues, main would need to knows about the side that has to finish for completeness to be guaranteed, which seems like it will be the side that is filling the queue, right? So lets say that threads will normally fall into the three camps, that I'll call producers, filters and processors. Producers are anything that produces data into the message passing system but is not feeding from a queue to get its orders. Filters are anything that is queue or message-event driven but also write their results to a queue / mailbox, and consumers, anything queue-fed but not sending output into queues. Queue fed here means not just that they read from queues some of the time but that they can always be expected to look at the queue for their next input and aren't going to be done until the queue is 'dry' or contains a shutdown command. Given that blob of definitions, what does main need to do? I would say that we can treat the whole graph of components as directional. The consumers are downstream, the filters are upstream, and the producers are as far up the creek as you can get. I think main needs the tids of all the producers and needs to either wait on all of them for shutdown messages or tell them all to shut down when needed. Hmmm... Maybe we can allow the threads to tell us these relationships -- threads could specify other threads they depend on or simply are watching. When any (or all, configurably?) of a thread's dependencies disappear the thread gets an OOB message which it can handle if needed. All threads default to depending on main; however, main could store its Tid somewhere and maybe a Thread could even use this to intentionally remove this dependency (e.g. it doesn't wanna die when main goes away). Similarly, a thread could find out which other threads depend on it. Main could check if it has any dependents, if desired... (these last bits is kind of off the cuff, so maybe there are huge problems with them.) Kevin -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.puremagic.com/pipermail/dmd-concurrency/attachments/20100121/74e8f6d2/attachment-0001.htm> |
January 21, 2010 [dmd-concurrency] Shutdown protocol | |
|---|---|
Posted in reply to Kevin Bealer | Kevin Bealer wrote: > Assuming one reader. What about a scenario where there are several each > of readers and writers, maybe the data flow of 'diff' as a simple example? In that case my analysis doesn't stand. A different approach should be devised. > In this case we should assume that main knows the tids of all the > readers rather than running them directly as in the two thread file copy > example. More generally, for any set of queues, main would need to > knows about the side that has to finish for completeness to be > guaranteed, which seems like it will be the side that is filling the > queue, right? For general queues, a end-of-stream signal must travel. Michel made a good point that I should better define solid protocols even in simple examples, so I'll change the code accordingly. > So lets say that threads will normally fall into the three camps, that > I'll call producers, filters and processors. [snip] > Main could check if it has any dependents, if desired... (these last > bits is kind of off the cuff, so maybe there are huge problems with them.) This makes sense, but at this point I'd avoid classifications that don't have a precedent. If Erlang made it without thread kinds, we should too. Andrei |
January 21, 2010 [dmd-concurrency] Shutdown protocol | |
|---|---|
Posted in reply to Andrei Alexandrescu | Le 2010-01-21 ? 3:14, Andrei Alexandrescu a ?crit : >> So lets say that threads will normally fall into the three camps, that I'll call producers, filters and processors. > [snip] >> Main could check if it has any dependents, if desired... (these last bits is kind of off the cuff, so maybe there are huge problems with them.) > > This makes sense, but at this point I'd avoid classifications that don't have a precedent. If Erlang made it without thread kinds, we should too. Erlang has the notion of links between threads (or should I say process?). If you link thread B to thread A, when thread A completes thread B receives a message to that effect. The default action is to do nothing if thread A exited normally and abort if thread A exited abnormally. But of course thread B can handle the message differently. When you think about it, it's pretty much what I proposed we do at the beginning of this thread. The difference were that I was proposing threads to be linked automatically with spawn (erlang use spawn_linked for this) and that threads get a shutdown message automatically when the owner thread terminates, terminating the thread by default (erlang only do this for abnormal termination, although you can change that behaviour in the linked thread's message handler). I'm no expert on erlang, but that's what I understood from what I read (and cited on this list) yesterday. -- Michel Fortin michel.fortin at michelf.com http://michelf.com/ |
January 21, 2010 [dmd-concurrency] Shutdown protocol | |
|---|---|
Posted in reply to Andrei Alexandrescu | On Jan 21, 2010, at 12:14 AM, Andrei Alexandrescu wrote:
> Kevin Bealer wrote:
>
>> So lets say that threads will normally fall into the three camps, that I'll call producers, filters and processors.
> [snip]
>> Main could check if it has any dependents, if desired... (these last bits is kind of off the cuff, so maybe there are huge problems with them.)
>
> This makes sense, but at this point I'd avoid classifications that don't have a precedent. If Erlang made it without thread kinds, we should too.
To be fair, Erlang also doesn't have this shutdown behavior.
|
January 21, 2010 [dmd-concurrency] Shutdown protocol | |
|---|---|
Posted in reply to Sean Kelly | Sean Kelly wrote: > On Jan 21, 2010, at 12:14 AM, Andrei Alexandrescu wrote: > >> Kevin Bealer wrote: >> >>> So lets say that threads will normally fall into the three camps, that I'll call producers, filters and processors. >> [snip] >>> Main could check if it has any dependents, if desired... (these last bits is kind of off the cuff, so maybe there are huge problems with them.) >> This makes sense, but at this point I'd avoid classifications that don't have a precedent. If Erlang made it without thread kinds, we should too. > > To be fair, Erlang also doesn't have this shutdown behavior. There are two precedents for the proposed shutdown behavior. One is the behavior of sockets in both Unix and Windows networking library. The libraries have one entry point for shutting down the entire library, after which all pending or new calls fail immediately. For example, quoting from http://msdn.microsoft.com/en-us/library/aa384350%28VS.85%29.aspx "The function terminates any pending operations on the handle and discards any outstanding data. If a thread is blocking a call to Wininet.dll, another thread in the application can call InternetCloseHandle on the Internet handle being used by the first thread to cancel the operation and unblock the first thread." This is why you can close a browser instantly even though there may be a dozen pages still waiting to load. The second is Java's experiment ThreadDeath: http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ThreadDeath.html That experiment failed because they couldn't find a reliable method for transforming the exception from aysnchronous to synchronous. My idea combines these two. Andrei |
January 21, 2010 [dmd-concurrency] Shutdown protocol | |
|---|---|
Posted in reply to Andrei Alexandrescu | ----- Original Message ----
> From: Andrei Alexandrescu <andrei at erdani.com>
>
> "The function terminates any pending operations on the handle and discards any
> outstanding data. If a thread is blocking a call to Wininet.dll, another thread
> in the application can call InternetCloseHandle on the Internet handle being
> used by the first thread to cancel the operation and unblock the first thread."
>
> This is why you can close a browser instantly even though there may be a dozen
> pages still waiting to load.
I disagree. A browser "closing instantly" just means its UI is hidden. Watch the process in Task Manager, it lingers for quite a few seconds.
-Steve
|
January 21, 2010 [dmd-concurrency] Shutdown protocol | |
|---|---|
Posted in reply to Steve Schveighoffer | Steve Schveighoffer wrote:
> ----- Original Message ----
>
>> From: Andrei Alexandrescu <andrei at erdani.com>
>>
>> "The function terminates any pending operations on the handle and discards any
>> outstanding data. If a thread is blocking a call to Wininet.dll, another thread
>> in the application can call InternetCloseHandle on the Internet handle being
>> used by the first thread to cancel the operation and unblock the first thread."
>>
>> This is why you can close a browser instantly even though there may be a dozen
>> pages still waiting to load.
>
> I disagree. A browser "closing instantly" just means its UI is hidden. Watch the process in Task Manager, it lingers for quite a few seconds.
The actual process shutdowns next to instantly on all my computers. I
can say I'm positive it does not use the method you are suggesting in
your other message (readWithShutdown).
Andrei
|
January 21, 2010 [dmd-concurrency] Shutdown protocol | |
|---|---|
Posted in reply to Andrei Alexandrescu | ----- Original Message ----
> From: Andrei Alexandrescu <andrei at erdani.com>
> Steve Schveighoffer wrote:
> > ----- Original Message ----
> >
> >> From: Andrei Alexandrescu
> >>
> >> "The function terminates any pending operations on the handle and discards
> any outstanding data. If a thread is blocking a call to Wininet.dll, another
> thread in the application can call InternetCloseHandle on the Internet handle
> being used by the first thread to cancel the operation and unblock the first
> thread."
> >>
> >> This is why you can close a browser instantly even though there may be a
> dozen pages still waiting to load.
> >
> > I disagree. A browser "closing instantly" just means its UI is hidden. Watch
> the process in Task Manager, it lingers for quite a few seconds.
>
> The actual process shutdowns next to instantly on all my computers. I can say
> I'm positive it does not use the method you are suggesting in your other message
> (readWithShutdown).
>
I can't say what method it uses to shut down. I don't see how you can either unless you read the code.
What I can say is I've seen Firefox linger and even hang when I shut it down. Often times I accidentally shut down firefox, and go to reopen it in about 5 seconds, and it says it can't start because there's already a process running and that process is shutting down. Clearly it does some sort of cleanup, whether part of that is to wait for socket reads to time out, I'm not sure.
My larger point, however, is that the socket-shutdown facility you want to have is available to D applications. But making it a *required* part is too much. Maybe applications that don't shut down using this method don't make it on to your laptop, but that's hardly a reason to require all D applications to do it. You are not the only user of D applications, and web browsing is not the only use-case for threading and sockets.
-Steve
|
January 21, 2010 [dmd-concurrency] Shutdown protocol | |
|---|---|
Posted in reply to Steve Schveighoffer | Exactly. I would love having some way to designate a master thread,
but I don't want it imposed on me.
Sent from my iPhone
On Jan 21, 2010, at 9:27 AM, Steve Schveighoffer <schveiguy at yahoo.com>
wrote:
> ----- Original Message ----
>
>> From: Andrei Alexandrescu <andrei at erdani.com>
>> Steve Schveighoffer wrote:
>>> ----- Original Message ----
>>>
>>>> From: Andrei Alexandrescu
>>>>
>>>> "The function terminates any pending operations on the handle and
>>>> discards
>> any outstanding data. If a thread is blocking a call to
>> Wininet.dll, another
>> thread in the application can call InternetCloseHandle on the
>> Internet handle
>> being used by the first thread to cancel the operation and unblock
>> the first
>> thread."
>>>>
>>>> This is why you can close a browser instantly even though there
>>>> may be a
>> dozen pages still waiting to load.
>>>
>>> I disagree. A browser "closing instantly" just means its UI is
>>> hidden. Watch
>> the process in Task Manager, it lingers for quite a few seconds.
>>
>> The actual process shutdowns next to instantly on all my computers.
>> I can say
>> I'm positive it does not use the method you are suggesting in your
>> other message
>> (readWithShutdown).
>>
>
> I can't say what method it uses to shut down. I don't see how you
> can either unless you read the code.
>
> What I can say is I've seen Firefox linger and even hang when I shut
> it down. Often times I accidentally shut down firefox, and go to
> reopen it in about 5 seconds, and it says it can't start because
> there's already a process running and that process is shutting
> down. Clearly it does some sort of cleanup, whether part of that is
> to wait for socket reads to time out, I'm not sure.
>
> My larger point, however, is that the socket-shutdown facility you
> want to have is available to D applications. But making it a
> *required* part is too much. Maybe applications that don't shut
> down using this method don't make it on to your laptop, but that's
> hardly a reason to require all D applications to do it. You are not
> the only user of D applications, and web browsing is not the only
> use-case for threading and sockets.
>
> -Steve
>
>
>
>
> _______________________________________________
> dmd-concurrency mailing list
> dmd-concurrency at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-concurrency
|
January 21, 2010 [dmd-concurrency] Shutdown protocol | |
|---|---|
Posted in reply to Andrei Alexandrescu | ----- Original Message ---- > From: Andrei Alexandrescu <andrei at erdani.com> > > Sean Kelly wrote: > > On Jan 21, 2010, at 12:14 AM, Andrei Alexandrescu wrote: > > > >> Kevin Bealer wrote: > >> > >>> So lets say that threads will normally fall into the three camps, that I'll > call producers, filters and processors. > >> [snip] > >>> Main could check if it has any dependents, if desired... (these last bits is > kind of off the cuff, so maybe there are huge problems with them.) > >> This makes sense, but at this point I'd avoid classifications that don't have > a precedent. If Erlang made it without thread kinds, we should too. > > > > To be fair, Erlang also doesn't have this shutdown behavior. > > There are two precedents for the proposed shutdown behavior. One is the behavior > of sockets in both Unix and Windows networking library. The libraries have one > entry point for shutting down the entire library, after which all pending or new > calls fail immediately. For example, quoting from > > http://msdn.microsoft.com/en-us/library/aa384350%28VS.85%29.aspx > > "The function terminates any pending operations on the handle and discards any > outstanding data. If a thread is blocking a call to Wininet.dll, another thread > in the application can call InternetCloseHandle on the Internet handle being > used by the first thread to cancel the operation and unblock the first thread." > > This is why you can close a browser instantly even though there may be a dozen > pages still waiting to load. This facility is http and ftp specific, and only works if you use Windows' WinInet library: "The Microsoft Windows Internet (WinINet) application programming interface (API) enables applications to access standard Internet protocols, such as FTP and HTTP. For ease of use, WinINet abstracts these protocols into a high-level interface." All sockets can be cleaned up with WSACleanup: http://msdn.microsoft.com/en-us/library/ms741549%28VS.85%29.aspx Which appears to do what you want -- except if you are calling it from DllMain: "The WSACleanup function typically leads to protocol-specific helper DLLs being unloaded. As a result, the WSACleanup function should not be called from the DllMain function in a application DLL. This can potentially cause deadlocks. For more information, please see the DLL Main Function." I don't think we should use this. -Steve |

Reply