digitalmars.D.learn - Proper way to code multithreaded applications?
- Jason House (17/17) May 31 2007 I've started writing a multithreaded application and I'm slowly hitting
- Regan Heath (8/26) Jun 01 2007 No, it's intended for when you want to wait for another thread to finish...
- Sean Kelly (33/51) Jun 01 2007 Well, it's an implementation issue that start() must basically call
- Regan Heath (3/8) Jun 01 2007 Oops, I didn't mean to imply nanosleep was available everywhere, I was t...
- Jason House (8/30) Jun 01 2007 I may not appreciate the full impact on performance, but I can pretty
- torhu (9/20) Jun 02 2007 I don't think you need more than this to fix that problem:
- Jason House (13/22) Jun 02 2007 Of course, that loses a lot of the functionality of derr.writefln, but
- Frank Benoit (8/33) Jun 02 2007 Hehe, this is no crash.
- torhu (10/24) Jun 02 2007 You probably know this, but since I've written it out already...
I've started writing a multithreaded application and I'm slowly hitting into different annoyances. I'm curious if anyone knows the proper way to handle some of these issues. * must call start to run a thread but thread execution starts with run (If that confuses, which it was intended to do. Make your own run method for what you want the thread to do but call the start function when you want the thread to begin) * wait can't be used inside a thread to wait for itself * yield has no specific timing constraints * derr is not synchronized. Debug output from different threads can get multiplexed together. * msleep isn't available on all platforms (problem inherited from C) * usleep isn't thread safe (problem inherited from C) My big issue at the moment is how to cause a thread to delay (approximately) for a period of time that I specify. I guess I might be ok with yield when the application is in full swing, but I really hate for nearly idle threads to peg the CPU when there's nothing to do.
May 31 2007
Jason House Wrote:I've started writing a multithreaded application and I'm slowly hitting into different annoyances. I'm curious if anyone knows the proper way to handle some of these issues. * must call start to run a thread but thread execution starts with run (If that confuses, which it was intended to do. Make your own run method for what you want the thread to do but call the start function when you want the thread to begin)Yep *shrug* those are perhaps bad method names.* wait can't be used inside a thread to wait for itselfNo, it's intended for when you want to wait for another thread to finish. You can't wait for yourself to finish because as long as you wait you're not finished.* yield has no specific timing constraintsNo.. it just calls Sleep(0); (on windows).* derr is not synchronized. Debug output from different threads can get multiplexed together.You're probably going to have to synchronize it yourself with a mutex or similar.* msleep isn't available on all platforms (problem inherited from C) * usleep isn't thread safe (problem inherited from C)Have you heard of nanosleep?My big issue at the moment is how to cause a thread to delay (approximately) for a period of time that I specify. I guess I might be ok with yield when the application is in full swing, but I really hate for nearly idle threads to peg the CPU when there's nothing to do.I reckon you write an msleep implementation which calls Sleep, msleep, usleep or nanosleep (depending on the platform) and call that. Regan Heath
Jun 01 2007
Jason House wrote:I've started writing a multithreaded application and I'm slowly hitting into different annoyances. I'm curious if anyone knows the proper way to handle some of these issues. * must call start to run a thread but thread execution starts with run (If that confuses, which it was intended to do. Make your own run method for what you want the thread to do but call the start function when you want the thread to begin)Well, it's an implementation issue that start() must basically call run() in the new thread. What I decided to do in Tango to lessen the confusion is to always have the user pass the method to run to the superclass if inheriting from Thread: class MyClass : Thread { this() { super( &run ); } void run() { ... } }* wait can't be used inside a thread to wait for itselfThe purpose of this method is to wait for the thread to complete, so if a thread could wait on itself the thread would effectively deadlock. In Tango this method is called join(), which is more consistent with popular terminology.* yield has no specific timing constraintsIt shouldn't. yield() is simply intended to yield the current thread's timeslice to another thread. On Win32, this is done via Sleep(0) or Sleep(1) (depending on how nice you want to be), and on Posix this is pthread_yield().* derr is not synchronized. Debug output from different threads can get multiplexed together.In my opinion, this is the correct choice from a performance standpoint.* msleep isn't available on all platforms (problem inherited from C) * usleep isn't thread safe (problem inherited from C)This is only an issue because Phobos threads lack a sleep() routine. Tango threads do not. And to reply to Regan as well, nanosleep isn't available everywhere either :-) The most commonly implemented methods are sleep() and usleep() in <unistd.h>. In fact, I think these may actually be required (nanosleep is a part of the realtime extensions IIRC).My big issue at the moment is how to cause a thread to delay (approximately) for a period of time that I specify. I guess I might be ok with yield when the application is in full swing, but I really hate for nearly idle threads to peg the CPU when there's nothing to do.You want sleep(), usleep(), or nanosleep() for Posix, and Sleep() or SleepEx() for Win32. Sean
Jun 01 2007
Sean Kelly Wrote:This is only an issue because Phobos threads lack a sleep() routine. Tango threads do not. And to reply to Regan as well, nanosleep isn't available everywhere either :-) The most commonly implemented methods are sleep() and usleep() in <unistd.h>. In fact, I think these may actually be required (nanosleep is a part of the realtime extensions IIRC).Oops, I didn't mean to imply nanosleep was available everywhere, I was trying to suggest what you did; to use sleep(), usleep(), or nanosleep() for Posix, and Sleep() or SleepEx() for Win32. ;) Regan Heath
Jun 01 2007
Sean Kelly wrote:Jason House wrote:I may not appreciate the full impact on performance, but I can pretty much guarantee that jumbling the output of two different threads together is rarely what the user wants to see...* derr is not synchronized. Debug output from different threads can get multiplexed together.In my opinion, this is the correct choice from a performance standpoint.It's annoying to have to worry about reentrant guarantees in addition to which are available on which platform. I notice tango's thread library has a sleep method that (theoretically) would solve the problem. I should add to my list that I don't see any mutexes in phobos.* msleep isn't available on all platforms (problem inherited from C) * usleep isn't thread safe (problem inherited from C)This is only an issue because Phobos threads lack a sleep() routine. Tango threads do not. And to reply to Regan as well, nanosleep isn't available everywhere either :-) The most commonly implemented methods are sleep() and usleep() in <unistd.h>. In fact, I think these may actually be required (nanosleep is a part of the realtime extensions IIRC).My big issue at the moment is how to cause a thread to delay (approximately) for a period of time that I specify. I guess I might be ok with yield when the application is in full swing, but I really hate for nearly idle threads to peg the CPU when there's nothing to do.You want sleep(), usleep(), or nanosleep() for Posix, and Sleep() or SleepEx() for Win32.
Jun 01 2007
Jason House wrote:Sean Kelly wrote:I don't think you need more than this to fix that problem: void debugOutput(char[] msg) { synchronized(derr) { derr.writeLine(msg); derr.flush(); // might be a good idea in case of redirection } }Jason House wrote:I may not appreciate the full impact on performance, but I can pretty much guarantee that jumbling the output of two different threads together is rarely what the user wants to see...* derr is not synchronized. Debug output from different threads can get multiplexed together.In my opinion, this is the correct choice from a performance standpoint.
Jun 02 2007
torhu wrote:I don't think you need more than this to fix that problem: void debugOutput(char[] msg) { synchronized(derr) { derr.writeLine(msg); derr.flush(); // might be a good idea in case of redirection } }Of course, that loses a lot of the functionality of derr.writefln, but something more advanced could be done... Sadly, that really isn't my big problem right now... I need to figure out how to sleep without crashing! Program received signal SIGUSR1, User defined signal 1. [Switching to Thread 1107310912 (LWP 30890)] 0x00002abf6306d881 in ?? () from /lib/libpthread.so.0 (gdb) up this= 0x2abf62c5f400) at search.d:131 131 nanosleep(&tv, null); Current language: auto; currently minimal
Jun 02 2007
Hehe, this is no crash. This is the garbage collector stopping all threads. You need to configure GDB to ignore SIGUSR1 and SIGUSR2. in GDB type handle SIGUSR1 nostop noprint handle SIGUSR2 nostop noprint or make a startup skript or something like that. Jason House schrieb:torhu wrote:I don't think you need more than this to fix that problem: void debugOutput(char[] msg) { synchronized(derr) { derr.writeLine(msg); derr.flush(); // might be a good idea in case of redirection } }Of course, that loses a lot of the functionality of derr.writefln, but something more advanced could be done... Sadly, that really isn't my big problem right now... I need to figure out how to sleep without crashing! Program received signal SIGUSR1, User defined signal 1. [Switching to Thread 1107310912 (LWP 30890)] 0x00002abf6306d881 in ?? () from /lib/libpthread.so.0 (gdb) up this= 0x2abf62c5f400) at search.d:131 131 nanosleep(&tv, null); Current language: auto; currently minimal
Jun 02 2007
Jason House wrote:torhu wrote:You probably know this, but since I've written it out already... void debugOutput(...) { synchronized(derr) { derr.writefx(_arguments, _argptr, true); derr.flush(); } } Sorry I can't help you with the other problem, haven't run into that.I don't think you need more than this to fix that problem: void debugOutput(char[] msg) { synchronized(derr) { derr.writeLine(msg); derr.flush(); // might be a good idea in case of redirection } }Of course, that loses a lot of the functionality of derr.writefln, but something more advanced could be done...
Jun 02 2007