| Thread overview | |||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
December 06, 2008 druntime thread_needLock() | ||||
|---|---|---|---|---|
| ||||
According to both the docs and my own experiments, thread_needLock() in core.thread returns a bool that depends on whether the current process has *ever* been multithreaded at *any* point in its execution. In Phobos's GC (pre-druntime), a similar function existed, but it returned a bool based on whether more than 1 thread was *currently* running. It seems to me that omitting locks should be safe if no more than 1 thread is currently running, even if more than 1 was running at some point in the past. Why is druntime's thread_needLock() designed the way it is? | ||||
December 06, 2008 Re: druntime thread_needLock() | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dsimcha | dsimcha wrote:
> According to both the docs and my own experiments, thread_needLock() in
> core.thread returns a bool that depends on whether the current process has
> *ever* been multithreaded at *any* point in its execution. In Phobos's GC
> (pre-druntime), a similar function existed, but it returned a bool based on
> whether more than 1 thread was *currently* running. It seems to me that
> omitting locks should be safe if no more than 1 thread is currently running,
> even if more than 1 was running at some point in the past. Why is druntime's
> thread_needLock() designed the way it is?
Typically, the stores of a terminating thread are only guaranteed to be visible when join() returns for that thread... and then to the joining thread only. While it's true that the stores will eventually be visible to all threads in a program, there's no easy way to figure out exactly when this is (the lock-free people would probably say you'd have to wait for a "quiescent state"). I also don't know of any apps that are multi threaded for a while and then later become single threaded, so the issue of performance loss seems like somewhat of a corner case.
Sean
| |||
December 06, 2008 Re: druntime thread_needLock() | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dsimcha | On 2008-12-06 06:02:44 +0100, dsimcha <dsimcha@yahoo.com> said:
> According to both the docs and my own experiments, thread_needLock() in
> core.thread returns a bool that depends on whether the current process has
> *ever* been multithreaded at *any* point in its execution. In Phobos's GC
> (pre-druntime), a similar function existed, but it returned a bool based on
> whether more than 1 thread was *currently* running. It seems to me that
> omitting locks should be safe if no more than 1 thread is currently running,
> even if more than 1 was running at some point in the past. Why is druntime's
> thread_needLock() designed the way it is?
Indeed I see no real reason not to keep a thread could that would be incremented before spawn or in thread_attach, and decremented at the end of thread_entryFunction and thread_detach.
Potentially one could think badly written code similar to this
if (thread_needLock()) lock();
if (thread_needLock()) unlock();
or initializations done unconditionally when the runtime becomes multithreaded,
but I found no issues like this in tangos runtime, thread_needLock is used only to then do synchronized(...){...}
So yes one could probably switch back to the old Phobos style.
I would guess that it is not really a common situation for a program to become single threaded again, though...
Fawzi
| |||
December 06, 2008 Re: druntime thread_needLock() | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | On 2008-12-06 08:33:40 +0100, Sean Kelly <sean@invisibleduck.org> said:
> dsimcha wrote:
>> According to both the docs and my own experiments, thread_needLock() in
>> core.thread returns a bool that depends on whether the current process has
>> *ever* been multithreaded at *any* point in its execution. In Phobos's GC
>> (pre-druntime), a similar function existed, but it returned a bool based on
>> whether more than 1 thread was *currently* running. It seems to me that
>> omitting locks should be safe if no more than 1 thread is currently running,
>> even if more than 1 was running at some point in the past. Why is druntime's
>> thread_needLock() designed the way it is?
>
> Typically, the stores of a terminating thread are only guaranteed to be visible when join() returns for that thread... and then to the joining thread only. While it's true that the stores will eventually be visible to all threads in a program, there's no easy way to figure out exactly when this is (the lock-free people would probably say you'd have to wait for a "quiescent state"). I also don't know of any apps that are multi threaded for a while and then later become single threaded, so the issue of performance loss seems like somewhat of a corner case.
>
>
> Sean
ok so this is the reason, good to know...
Fawzi
| |||
December 06, 2008 Re: druntime thread_needLock() | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Fawzi Mohamed | On 2008-12-06 09:44:06 +0100, Fawzi Mohamed <fmohamed@mac.com> said:
> On 2008-12-06 08:33:40 +0100, Sean Kelly <sean@invisibleduck.org> said:
>
>> dsimcha wrote:
>>> According to both the docs and my own experiments, thread_needLock() in
>>> core.thread returns a bool that depends on whether the current process has
>>> *ever* been multithreaded at *any* point in its execution. In Phobos's GC
>>> (pre-druntime), a similar function existed, but it returned a bool based on
>>> whether more than 1 thread was *currently* running. It seems to me that
>>> omitting locks should be safe if no more than 1 thread is currently running,
>>> even if more than 1 was running at some point in the past. Why is druntime's
>>> thread_needLock() designed the way it is?
>>
>> Typically, the stores of a terminating thread are only guaranteed to be visible when join() returns for that thread... and then to the joining thread only. While it's true that the stores will eventually be visible to all threads in a program, there's no easy way to figure out exactly when this is (the lock-free people would probably say you'd have to wait for a "quiescent state"). I also don't know of any apps that are multi threaded for a while and then later become single threaded, so the issue of performance loss seems like somewhat of a corner case.
>>
>>
>> Sean
>
> ok so this is the reason, good to know...
>
> Fawzi
a memory barrier would be needed, and atomic decrements, but I see that it is not portable...
| |||
December 06, 2008 Re: druntime thread_needLock() | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly, el 5 de diciembre a las 23:33 me escribiste: > dsimcha wrote: > >According to both the docs and my own experiments, thread_needLock() in core.thread returns a bool that depends on whether the current process has *ever* been multithreaded at *any* point in its execution. In Phobos's GC (pre-druntime), a similar function existed, but it returned a bool based on whether more than 1 thread was *currently* running. It seems to me that omitting locks should be safe if no more than 1 thread is currently running, even if more than 1 was running at some point in the past. Why is druntime's thread_needLock() designed the way it is? > > Typically, the stores of a terminating thread are only guaranteed to be visible when join() returns for that thread... and then to the joining thread only. While it's true that the stores will eventually be visible to all threads in a program, there's no easy way to figure out exactly when this is (the lock-free people would probably say you'd have to wait for a "quiescent state"). I also don't know of any apps that are multi threaded for a while and then later become single threaded, so the issue of performance loss seems like somewhat of a corner case. FYI, I've added this to the druntime FAQ: http://www.dsource.org/projects/druntime/wiki/DevelFAQ -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Karma police arrest this man, he talks in maths, he buzzes like a fridge, he's like a detuned radio. | |||
December 06, 2008 Re: druntime thread_needLock() | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Fawzi Mohamed | Fawzi Mohamed wrote:
> So yes one could probably switch back to the old Phobos style.
> I would guess that it is not really a common situation for a program to become single threaded again, though...
>
> Fawzi
>
At work, we have a single-threaded application -- everything happens on the GUI thread. There are some operations that take a long time, though. For those, we throw up a spinny dialog box. But if these operations happened on the GUI thread, the spinny dialog box would not spin. So we do the expensive operations on a background thread.
So, our application becomes multithreaded on rare occasions and becomes single-threaded again after.
Not sure how common this is.
| |||
December 06, 2008 Re: druntime thread_needLock() | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Christopher Wright | Christopher Wright, el 6 de diciembre a las 09:06 me escribiste: > Fawzi Mohamed wrote: > >So yes one could probably switch back to the old Phobos style. > >I would guess that it is not really a common situation for a program to become single threaded again, though... > >Fawzi > > At work, we have a single-threaded application -- everything happens on the GUI thread. There are some operations that take a long time, though. For those, we throw up a spinny dialog box. But if these operations happened on the GUI thread, the spinny dialog box would not spin. So we do the expensive operations on a background thread. > > So, our application becomes multithreaded on rare occasions and becomes single-threaded again after. > > Not sure how common this is. I think this is pretty common in GUI applications, but I don't think GUI applications usually are performance critical, right? -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- You can do better than me. You could throw a dart out the window and hit someone better than me. I'm no good! -- George Constanza | |||
December 06, 2008 Re: druntime thread_needLock() | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Fawzi Mohamed | Fawzi Mohamed wrote:
>
> a memory barrier would be needed, and atomic decrements, but I see that it is not portable...
It would also somewhat defeat the purpose of thread_needLock, since IMO this routine should be fast. If memory barriers are involved then it may as well simply use a mutex itself, and this is exactly what it's intended to avoid.
Sean
| |||
December 06, 2008 Re: druntime thread_needLock() | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | On 2008-12-06 17:13:34 +0100, Sean Kelly <sean@invisibleduck.org> said:
> Fawzi Mohamed wrote:
>>
>> a memory barrier would be needed, and atomic decrements, but I see that it is not portable...
>
> It would also somewhat defeat the purpose of thread_needLock, since IMO this routine should be fast. If memory barriers are involved then it may as well simply use a mutex itself, and this is exactly what it's intended to avoid.
the memory barrier would be needed in the code that decrements the number of active threads, so that you are sure that no pending writes are still there, (that is the problem that you said brought you to switch to a multithreaded flag), not in the code of thread_needLock...
But again I would say that this optimization is not really worth it (as you also said it), even if it is relevant for GUI applications.
Fawzi
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply