I'm seeing some very strange behavior with my program. On initialization, a number of threads are started that are simply going into a busy loop. When the program stops, its Cleanup() routine stops all those threads. Should be nothing to it.
Things work great on the first execution. For subsequent executions, the program initializes just fine, but somewhere along the way - after it enters its "command loop" (which just waits for input from scanf) it is KILLED right away.
What?!?!
Now, Prophet has been using pthreads all along for user input. A user emailed me about six months ago and told me that Prophet simply died right away on his Mac. I don't have a Mac (I use Gentoo Linux), and I was never able to reproduce this problem. I wonder if it's related...
all I can say is that I gave up on pthreads a few years ago. I found too many inconsistencies between the various unix and linux implementations. CPU time was problematic as some systems return the cpu time for a thread, while others return the accumulated time for all threads. scheduling policies varied (some systems default to one real process and round-robin the threads on that one process which won't use more than one CPU, unless you add specific thread-scheduling policy calls). I decided to go to "fork()" and roll my own to get away from all the nonsense and have not regretted that decision.
I notice you have a loop iterating on i, and you are passing the _address_ of I to the new thread. By the time that thread executes, i will probably be at limit+1 which is almost certainly not what you want. Don't pass the address of that, pass the actual value. Note that the create function requires a pointer, but you can recast the value "i" to a (void *) and then in the new thread re-cast it back to an int. Then you are no longer passing a pointer to a value that will be changed many times by the time the thread has been created and gets scheduled.
Also make absolutely certain you understand the difference between these:
volatile int X;
volatile int *X;
int * volatile X;
volatile int * volatile X;
they are absolutely not the same thing and you have to be sure that anything that can be changed in another thread is declared volatile or compiler optimization will kill you.
I agree with Bob. I've coded pthreads, Open MP and a few other libs that some groups seem stuck on. Each one has missing parts -- the developers decided not to provide that functionality because using it can cause errors.
Bob is right that there are resource usage metering differences among varying pthread implementations; I've seen this between Linux and OpenBSD. Which has the bug? It depends on who you talk with.
Linux threads are essentially lightweight processes and are managed as such, so a fork only approach is going to work pretty much the same as a pthread approach. On the various BSD systems it's a different story and so a pthread deployment is likely to be more efficient than a simple fork.
Symbolic uses pthreads, but it doesn't use any advanced pthread features other than customization of per thread stack space allocation. The idea is to avoid an unnecessary triggering of platform specific idiosyncrasies.
sje wrote:Bob is right that there are resource usage metering differences among varying pthread implementations; I've seen this between Linux and OpenBSD. Which has the bug? It depends on who you talk with.
Linux threads are essentially lightweight processes and are managed as such, so a fork only approach is going to work pretty much the same as a pthread approach. On the various BSD systems it's a different story and so a pthread deployment is likely to be more efficient than a simple fork.
Symbolic uses pthreads, but it doesn't use any advanced pthread features other than customization of per thread stack space allocation. The idea is to avoid an unnecessary triggering of platform specific idiosyncrasies.
I don't see any efficiency issue at all between pthreads and fork(). Almost all O/S's today use copy-on-write making process creation very fast.
The main difference is that pthreads shares everything that is global, while with fork() you have to explicitly share things (I use the SYSV shared memory stuff since that seems to work across every unix platform I have tried).
Even when I used pthreads, all I used was pthread_create, since I never want to kill/restart threads as the cost is still expensive enough to not do it inside the tree. I never used mutex locks as the overhead is beyond bearable and it murders efficiency if things are locked/unlocked frequently.
But the main thing I hated was the bugs. Fork() has to work or unix won't work. But the tacked-on thread library may or may not work, depending on random events and/or cosmic ray exposure..
bob wrote:I notice you have a loop iterating on i, and you are passing the _address_ of I to the new thread. By the time that thread executes, i will probably be at limit+1 which is almost certainly not what you want. Don't pass the address of that, pass the actual value. Note that the create function requires a pointer, but you can recast the value "i" to a (void *) and then in the new thread re-cast it back to an int. Then you are no longer passing a pointer to a value that will be changed many times by the time the thread has been created and gets scheduled.
I do something similar to James but I'm not quite understanding the above. Can you give a quick example of why passing the pointer value would be wrong? Also I guess you have to worry about the type of int as for 64-bits exe I guess pointers are 64-bits. http://www.opengroup.org/pubs/online/79 ... reate.html
Also make absolutely certain you understand the difference between these:
volatile int X;
volatile int *X;
int * volatile X;
volatile int * volatile X;
they are absolutely not the same thing and you have to be sure that anything that can be changed in another thread is declared volatile or compiler optimization will kill you.