This topic is 3970 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hey. I’ve been experimenting on a multithreaded engine. It works on the following principal: I have a main thread, which handles the message loop etc. It also runs the kernel object which has a list of ‘tasks’, which it updates every frame. The idea is to have one ‘main’ task which syncs per frame with my ThreadedExecutor(s) Then I have a system I call ThreadedExecutor, which is in essence the same as my kernel, which has a list of tasks, but it runs on a single thread per ThreadedExecutor. This is an excerpt from my ThreadedExecutor procedure, of which I currently use 2 instances:
// Loop till the kernel notifies a close event
while(WaitForSingleObject(this-&gt;m_hCloseEvent, 0) != WAIT_OBJECT_0)
{
// Wait for main thread to acknowledge
WaitForSingleObject(this-&gt;m_hSyncStartHandle, INFINITE);
// Tell main thread were working
// Call all active tasks' Update function
{
}
// Wait for main thread to tell us it's done with its work
// I'm not sure if this is needed, but doesn't work without it
WaitForSingleObject(this-&gt;m_hSyncEndHandle, INFINITE);
}


// Wait for threads to finish with previous task
if(WaitForMultipleObjects(2, &handles[0], true, 0) == 0)
{
// Tell threads I'm not done anymore
// Maby not needed, but it doesn't work without this
ResetEvent(handles[3]);
// Tell threads they can start working
SetEvent(handles[2]);
//WHY DOESN'T IT WORK WITHOUT THIS LINE
_kbhit();
//OR THIS LINE
//Sleep(1);
//Do rendering or whatever
//	...
// Tell threads to stop working when they're done
ResetEvent(handles[2]);
// Tell threads I'm done with a frame
SetEvent(handles[3]);
}


For some unknown reason my threads don’t sync if I don’t call _kbhit() or Sleep(x). I checked the kbhit code, and found these lines to do the same as _kbhit():
GetNumberOfConsoleInputEvents(console, &num);
events = new INPUT_RECORD[num];
PeekConsoleInput(console, events, num, &num);
SAFE_DELETE_ARRAY(events);


What in these functions cause this phenomenon? If I don’t do any of these fragments it doesn’t sync. WHY?? I’m sure there are better ways to sync threads also. Any ideas please? Thanks [Edited by - Climax777 on December 31, 2007 5:41:43 PM]

##### Share on other sites
Sounds like you have a single threaded processor and one thread is taking all of the resources. 'source' in square brackets will put your source into nice boxes making it mildly more legible...

##### Share on other sites
Quote:
 Original post by TelastynSounds like you have a single threaded processor and one thread is taking all of the resources. 'source' in square brackets will put your source into nice boxes making it mildly more legible...

I have a dual core AMD Athlon 64 X2 4200+. I've monitored the cpu usage and I assure you it's not the problem. It doesn't matter what work load I put on the cores or threads.

The only thing is that if I dont put in that line (_kbhit) or (Sleep()) it doesn't sync.

But when it syncs I get amazing performance.

What can I do?

PS I hope the code is better :P

##### Share on other sites
I don't know how your code is supposed to behave, but this bit is suspect (kbhit and comments removed for clarity):
	SetEvent(handles[2]);	ResetEvent(handles[2]);

There should be some kind of delay between them so that the other threads have a chance to see the SetEvent. any piece of code can work as a delay but then you never really know if your timeslice will end at just the right moment. Probably this means you need to change your architecture slightly.

[Edited by - wendigo23 on December 31, 2007 6:09:16 PM]

##### Share on other sites
Quote:
 Original post by wendigo23I don't know how your code is supposed to behave, but this bit is suspect (kbhit and comments removed for clarity):*** Source Snippet Removed ***Should it be set or reset? It can't be both.

The idea is that the code inbetween has to be longer than the WaitForSingleObject() in the ThreadedExecutor. That way there can't be any unwanted prestarts, before the end of the current frame. The last handle(handle[3]) is a block used to ensure that the threads don't continue until the main thread has started again.

Let me restate my logic:

When considering my main thread - The first thing is I wait for the threads to finish processing. When the if statement gets a true, I reset the event that indicates that the main thread is finished. This imples that the main thread is going to work.

The second event I SET, is the event telling my threads that they can start working.

Then my main thread should do some work (and _kbhit) and then reset the event letting my threads know they shouldn't continue working after I set the last event, which tells my thread that the frame is done.

The if is only there to test if the thread should close and is not used for syncing.

Then the event is set telling the main thread that this one is ready. Then it waits for the main thread to acknowledge (handles[2] in the main thread).

Then the event is reset, indicating that the thread is going to work now.

Then the thread works and waits for the final sync event (handels[3] in main thread.

##### Share on other sites
Quote:
 The idea is that the code inbetween has to be longer than the WaitForSingleObject() in the ThreadedExecutor

That's your problem. You shouldn't rely on any kind of magic timing behavior. Perhaps the other thread should Reset it after it has successfully waited.

##### Share on other sites
Quote:
Original post by wendigo23
Quote:
 The idea is that the code inbetween has to be longer than the WaitForSingleObject() in the ThreadedExecutor

That's your problem. You shouldn't rely on any kind of magic timing behavior. Perhaps the other thread should Reset it after it has successfully waited.

I tried that, but I noticed that sometimes the two worker threads would miss the set event, because they have different work loads.

But the timing isn't the issue. If I put a long workload in the main thread it still doesn't sync. But no matter the size of any workloads, it syncs perfectly if I use _kbhit

##### Share on other sites
What is the minimum amount of events/mutexes/semaphores needed to sync a main thread and its x number of worker threads?

##### Share on other sites
No number of semaphores, mutexes, critical sections, or any other threading primitive can ensure that a multithreaded program will work correctly. The only way to make it work is to actually stop and look at what the threading primitives are doing and how you want the program to behave.

The cause of the current problem is that setting an event does not immediately cause threads waiting for that event to stop waiting. They will only stop waiting when they get a timeslice to run and can see that the event is set. Sleep or the kbhit (which has to wait to synchronize with the console) cause the main thread to give up its timeslice, giving the other threads a chance to run while the event is set (although it is not strictly required that the scheduler always give them this chance).

Your second problem, the "not sure if this is necessary but it doesn't work without it" event, is a temporary fix just like the sleep or kbhit. If the executors did not wait for this event, they'd loop around, see that the start event is still set, and loop around for another iteration. The start event is still set because while the executor is running the main thread is not. The main thread may still be waiting to return from the kbhit, so the start event was never reset.

Maybe you're more familiar with java's threading model, where waiting threads immediately stop waiting when the object they were waiting on is signaled? Or in any case, that seems to be the way you're trying to use the events. In windows programming, this corresponds to critical sections and condition variables (all the way down to weirdness like threads occasionally walking up even when not told to, requiring a little extra care when using them); they are designed for use within a single process, and may be more efficient than events (which can be used for interprocess communication).

Anyway, the way you're trying to use the events, it may be better to not have the events threads reset the same events that they set. The thread waiting for the event should reset it, so that way when it gets back to the wait statement, the event will not be set unless some other thread set it. Giving each executor its own "frame start" event (instead of making them share) may simplify things; you can then configure the events to automatically reset when a thread is triggered by them, eliminating the need for explicit resets.

[Edited by - Vorpy on January 1, 2008 12:58:53 PM]

##### Share on other sites
Thanks Vorpy, it makes sense. I also didn't like the fix. I like stability.

So back to the drawing board hey? Thanks.

PS what are your thoughts on OpenMP? For ease of implementation it gets my vote, but I haven't tested for performance. I see games such as doom used it.

1. 1
2. 2
3. 3
4. 4
Rutin
13
5. 5

• 14
• 10
• 9
• 9
• 11
• ### Forum Statistics

• Total Topics
633692
• Total Posts
3013356
×