rvida wrote:
Contrary to my fears, the threading, locking and signaling stuff wasn't very hard to port. In case someone finds it useful here is my smp.h:
nice idiom, and probably it means we have a small leak in SF upon exiting. Can I ask how you sync on the threads upon termination ?
I mean, when Critter exits, in which way you are able to wait from the main thread that all the other threads are terminated if you don't keep an handle to the threads an so are unable to WaitForSingleObject() ?
typedef union {
int i;
struct {
short int eg_value;
short int mg_value;
} s;
} ScorePair;
Then you can write score.s.eg_value in stead of eg_value(score), and you can still access it as an int through score.i. Or do you rely on the order in which the two halves are stored in the int?
That seems broken if the structure members get aligned, unless there's any particular reason why that can't happen inside a union.
typedef union {
int i;
struct {
short int eg_value;
short int mg_value;
} s;
} ScorePair;
Then you can write score.s.eg_value in stead of eg_value(score), and you can still access it as an int through score.i. Or do you rely on the order in which the two halves are stored in the int?
That seems broken if the structure members get aligned, unless there's any particular reason why that can't happen inside a union.
Most compilers (including GCC) default to natural alignment for primitive types ("aligned to same size as the type"). So the int is 4 bytes and has 4-byte alignment, and the shorts are 2 bytes and have 2-byte alignment. The union is 4 bytes and has 4-byte alignment.
If worried about weird compilers, you could put a static assert on the size (or you could just use your own user-defined types of known sizes and not worry about it).
mcostalba wrote:
I mean, when Critter exits, in which way you are able to wait from the main thread that all the other threads are terminated if you don't keep an handle to the threads an so are unable to WaitForSingleObject() ?
Thanks
Marco
I don't need the thread handle. In destructor of the Engine class I loop indefinitely until all helper threads have their state set to TS_TERMINATED (this is the last thing they do before returning from their idle loop).
mcostalba wrote:
I mean, when Critter exits, in which way you are able to wait from the main thread that all the other threads are terminated if you don't keep an handle to the threads an so are unable to WaitForSingleObject() ?
Thanks
Marco
I don't need the thread handle. In destructor of the Engine class I loop indefinitely until all helper threads have their state set to TS_TERMINATED (this is the last thing they do before returning from their idle loop).
for (int i = 0; i < MAX_THREADS; i++)
{
// Wake up all the slave threads and wait for termination
if (i != 0)
{
threads[i].do_terminate = true;
threads[i].wake_up();
while (threads[i].state != Thread::TERMINATED) {}
}
....
}
but i don't like a lot to reinvent the wheel with our home grown Thread::TERMINATED flag and I'd prefer to use the proper way documented for the thread library.
I am wondering what happens if we leave without waiting for thread termination, does the OS / thread library wait for us before to exit() and free the process space ?
mcostalba wrote:
I am wondering what happens if we leave without waiting for thread termination, does the OS / thread library wait for us before to exit() and free the process space ?
It seems to work under Windows, but has bad effects with pthreads, so I have hacked up this thread library dependent code to wait for threads to terminate instead of our home grown flag:
for (int i = 0; i < MAX_THREADS; i++)
{
// Wake up all the slave threads and wait for termination
if (i != 0)
{
threads[i].do_terminate = true;
threads[i].wake_up();
#if defined(_MSC_VER)
WaitForSingleObject(threads[i].handle, 0);
CloseHandle(threads[i].handle);
#else
pthread_join(threads[i].handle, NULL);
pthread_detach(threads[i].handle);
#endif
}
mcostalba wrote:
I am wondering what happens if we leave without waiting for thread termination, does the OS / thread library wait for us before to exit() and free the process space ?
It seems to work under Windows, but has bad effects with pthreads, so I have hacked up this thread library dependent code to wait for threads to terminate instead of our home grown flag:
for (int i = 0; i < MAX_THREADS; i++)
{
// Wake up all the slave threads and wait for termination
if (i != 0)
{
threads[i].do_terminate = true;
threads[i].wake_up();
#if defined(_MSC_VER)
WaitForSingleObject(threads[i].handle, 0);
CloseHandle(threads[i].handle);
#else
pthread_join(threads[i].handle, NULL);
pthread_detach(threads[i].handle);
#endif
}
I've never noticed a problem here. Program might not exit cleanly, but nothing bad should happen that I can think of...
bob wrote: I've never noticed a problem here. Program might not exit cleanly, but nothing bad should happen that I can think of...
Yes, I agree, we have never noticed problems too. Anyhow let the thread raising a flag, like TERMINATED, is intrinsically racy given that when the flag is raised the thread is of course still running, this probably has no practical consequence, anyhow because we are very nitpicking , is not the correct way to detect thread termination in the general case.