Using a critical section in a high priority thread
-
I want to share some data between a thread that has Realtime priority (24) with another thread that has Normal priority (8). The Realtime thread is sending events to a midiOut device, the Normal thread is telling the Realtime thread what volume to use for the events. I might be able to get away without using any sort of exclusion mechanism, but I want to play safe. I’m concerned that a timer interrupt might occur in the middle of a data write, causing the read to be corrupted. The obvious thing to do is to use a CRITICAL_SECTION, and to get both threads to do EnterCriticalSection()/LeaveCriticalSection() around the code that accesses the shared data. But I’m worried that doing EnterCriticalSection() in a Realtime thread will totally lock up Windows. So a few questions: 1) If the Normal thread calls EnterCriticalSection(), does that prevent timer interrupts from happening until it calls LeaveCriticalSection()? 2) If the Realtime thread runs when the Normal thread owns the critical section object, so that the call to EnterCriticalSection() in the Realtime thread cannot complete until the Normal thread has released ownership of the critical section object, will this cause any problems? I’m worried that the Normal thread won’t be able to run because it’s been interrupted, and the Realtime thread won’t be able to run because it’s waiting for the critical section object. 3) Will all 32-bit versions of Windows behave in the same way with regard to this possible problem? Thanks in advance. Chris.
-
I want to share some data between a thread that has Realtime priority (24) with another thread that has Normal priority (8). The Realtime thread is sending events to a midiOut device, the Normal thread is telling the Realtime thread what volume to use for the events. I might be able to get away without using any sort of exclusion mechanism, but I want to play safe. I’m concerned that a timer interrupt might occur in the middle of a data write, causing the read to be corrupted. The obvious thing to do is to use a CRITICAL_SECTION, and to get both threads to do EnterCriticalSection()/LeaveCriticalSection() around the code that accesses the shared data. But I’m worried that doing EnterCriticalSection() in a Realtime thread will totally lock up Windows. So a few questions: 1) If the Normal thread calls EnterCriticalSection(), does that prevent timer interrupts from happening until it calls LeaveCriticalSection()? 2) If the Realtime thread runs when the Normal thread owns the critical section object, so that the call to EnterCriticalSection() in the Realtime thread cannot complete until the Normal thread has released ownership of the critical section object, will this cause any problems? I’m worried that the Normal thread won’t be able to run because it’s been interrupted, and the Realtime thread won’t be able to run because it’s waiting for the critical section object. 3) Will all 32-bit versions of Windows behave in the same way with regard to this possible problem? Thanks in advance. Chris.
Hi Chris, 1) I don't think that I really do understand what you mean with timer interrupts, but the call to EnterCriticalSection() on the "normal" thread will cause the "realtime" thread to block on the EnterCriticalSection() call and this will give the processing cycles back to your "normal" thread, which will be happily executing until it calls LeaveCriticalSection(). Ie it is like having a high priority thread calling Sleep, so regardless of the priority of the thread, the processing time will be granted to other threads. 2) There is no need to worry about the "normal" thread, it will most probably still get the same amount of processing time (maybe even more than) that it used to get before. (Beware that I'm not saying that this processing time is enough for your normal thread to be 'responsive enough') The thing about the "realtime" thread is, you're correct it will block until the "normal" thread calls LeaveCriticalSection() so your realtime operation will probably stall. Instead of doing this you can call TryEnterCriticalSection on the realtime thread, and if it returns zero, you can skip trying to read that information and retry on the next loop. 3) As you probably already know, using real time priority in a thread is strongly discouraged and I'm not sure that all versions of Windows provides the same flexibility on multithreading (especially Win9x series) and you should expect lock-ups due to the realtime priority of your thread. Besides that, if you're concerned about corruption in single read-write's of 32bit values, I'd like to remind you that in Win32 all 32 bit operations are guaranteed to be atomic, so there is no need for synchronization if you're just reading from or writing to an integer from multiple threads. There will be no problem if in one thread you are just reading an integer and in the other thread just updating it.
-
I want to share some data between a thread that has Realtime priority (24) with another thread that has Normal priority (8). The Realtime thread is sending events to a midiOut device, the Normal thread is telling the Realtime thread what volume to use for the events. I might be able to get away without using any sort of exclusion mechanism, but I want to play safe. I’m concerned that a timer interrupt might occur in the middle of a data write, causing the read to be corrupted. The obvious thing to do is to use a CRITICAL_SECTION, and to get both threads to do EnterCriticalSection()/LeaveCriticalSection() around the code that accesses the shared data. But I’m worried that doing EnterCriticalSection() in a Realtime thread will totally lock up Windows. So a few questions: 1) If the Normal thread calls EnterCriticalSection(), does that prevent timer interrupts from happening until it calls LeaveCriticalSection()? 2) If the Realtime thread runs when the Normal thread owns the critical section object, so that the call to EnterCriticalSection() in the Realtime thread cannot complete until the Normal thread has released ownership of the critical section object, will this cause any problems? I’m worried that the Normal thread won’t be able to run because it’s been interrupted, and the Realtime thread won’t be able to run because it’s waiting for the critical section object. 3) Will all 32-bit versions of Windows behave in the same way with regard to this possible problem? Thanks in advance. Chris.
This is a fairly serious design issue. Windows is not a real time operating system, so you can't rely on it to do the right thing with regard to scheduling of threads in this way. The scenario you are describing with the thread being kicked off the CPU and struggling to get back on is 'priority inversion'. Understanding the windows threading model is difficult, and it takes time. One of the simplest ways to think of it is that the main thread (what I believe is your 'normal' thread) does nothing but handle the message pump (event queue). Messages in the main thread are dealt with in two ways, synchronously (PostMessage) or asynchronously (SendMessage). PostMessage forces events to be dealt with immediately, SendMessage buffers the messages in a queue to be dealt with in FIFO order. The main thread can only do one thing at a time, however it can be interrupted by another thread. If the main thread enters a critical section it prevents another thread from entering that region at the same time, until the main thread leaves the critical section. AFAIK another event having occured (a WM_TIMER message) is irrelevant because the timer message is buffered in the message pump. Like the last poster recommended, I suggest that you don't bother changing thread priorities unless you can show that this provides a significant benefit at the end of the day - 'premature optimisation is the root of all evil'. It may be that with a single thread at priority 24 the main thread won't get any CPU or enough CPU to run the GUI. 2) rely upon the operating system doing something reasonable at a low level - like giving non-blocked threads a chance on the CPU in preference to blocked threads. This sounds like you are worried about 'deadlocks' but they generally occur only in situations where multiple resources are in contention. Chris Hills wrote: 3) Will all 32-bit versions of Windows behave in the same way with regard to this possible problem? Yes, although apparently their are kernels now available which sit on top of Windows that minimise this problem, but they are fairly expensive, and probably not redistributable. If you do need an operating system which can avoid this problem look at something like MaRTE[^] Also, ensure that the frequency of WM_TIMER messages on the main thread occurs at the rate that you expect it too, especially with the priority of the main thread so
-
This is a fairly serious design issue. Windows is not a real time operating system, so you can't rely on it to do the right thing with regard to scheduling of threads in this way. The scenario you are describing with the thread being kicked off the CPU and struggling to get back on is 'priority inversion'. Understanding the windows threading model is difficult, and it takes time. One of the simplest ways to think of it is that the main thread (what I believe is your 'normal' thread) does nothing but handle the message pump (event queue). Messages in the main thread are dealt with in two ways, synchronously (PostMessage) or asynchronously (SendMessage). PostMessage forces events to be dealt with immediately, SendMessage buffers the messages in a queue to be dealt with in FIFO order. The main thread can only do one thing at a time, however it can be interrupted by another thread. If the main thread enters a critical section it prevents another thread from entering that region at the same time, until the main thread leaves the critical section. AFAIK another event having occured (a WM_TIMER message) is irrelevant because the timer message is buffered in the message pump. Like the last poster recommended, I suggest that you don't bother changing thread priorities unless you can show that this provides a significant benefit at the end of the day - 'premature optimisation is the root of all evil'. It may be that with a single thread at priority 24 the main thread won't get any CPU or enough CPU to run the GUI. 2) rely upon the operating system doing something reasonable at a low level - like giving non-blocked threads a chance on the CPU in preference to blocked threads. This sounds like you are worried about 'deadlocks' but they generally occur only in situations where multiple resources are in contention. Chris Hills wrote: 3) Will all 32-bit versions of Windows behave in the same way with regard to this possible problem? Yes, although apparently their are kernels now available which sit on top of Windows that minimise this problem, but they are fairly expensive, and probably not redistributable. If you do need an operating system which can avoid this problem look at something like MaRTE[^] Also, ensure that the frequency of WM_TIMER messages on the main thread occurs at the rate that you expect it too, especially with the priority of the main thread so
I think you got this backwards: "PostMessage forces events to be dealt with immediately, SendMessage buffers the messages in a queue to be dealt with in FIFO order." I am pretty sure SendMessage dispatches message into the receiver's message queue immediately and PostMessage will add it to the queue.
-
I think you got this backwards: "PostMessage forces events to be dealt with immediately, SendMessage buffers the messages in a queue to be dealt with in FIFO order." I am pretty sure SendMessage dispatches message into the receiver's message queue immediately and PostMessage will add it to the queue.
Blake Miller wrote: I think you got this backwards: :-O Whoops. Of course you're correct :doh:
If you can keep you head when all about you Are losing theirs and blaming it on you; If you can dream - and not make dreams your master; If you can think - and not make thoughts your aim; Yours is the Earth and everything that's in it. Rudyard Kipling