티스토리 뷰

A ready-to-use condition class for WIN32 ;)

class Condition {
private:
    HANDLE m_condition;
        Condition( const Condition& ) {} // non-copyable
        public:
            Condition() {
                    m_condition = CreateEvent( NULL, TRUE, FALSE, NULL );
                        }
                            ~Condition() {
                                    CloseHandle( m_condition );
                                        }
                                            void Wait() {
                                                    WaitForSingleObject( m_condition, INFINITE );
                                                            ResetEvent( m_condition );
                                                                }
                                                                    bool Wait( uint32 ms ) {
                                                                            DWORD result = WaitForSingleObject( m_condition, (DWORD)ms );
                                                                                    ResetEvent( m_condition );
                                                                                            return result == WAIT_OBJECT_0;
                                                                                                }
                                                                                                    void Signal() {
                                                                                                            SetEvent( m_condition );
                                                                                                                }
                                                                                                                };
                                                                                                                

Usage:

// inside one of the standard worker child threads...
if( time_for_one_of_those_intermittent_calculations_to_be_done() ) {
    global_flag_set = TRUE;
        condition.Signal();
        }
        
        
        // inside the special (N+1)th thread
        for(;;) {
            if( global_flag_set==FALSE ) {
                    condition.Wait(); // sends thread to sleep, until signalled
                        }
                            if (global_flag_set == TRUE) {
                                    perform_big_calculation();
                                            global_flag_set = FALSE;
                                                }
                                                }
                                                

NOTE: you have to add a lock (e.g. a critical section) around global_flag_set. And also in most cases the flag should be replaced with a queue or at least a counter (a thread could signal multiple times while 'special' thread is performing its calculations).

-------------------

You should check out the WaitForSingleObject and WaitForMultipleObjects functions in the Windows API.

WaitForMultipleObjects

-------------------

Yes. Use condition variables. If you sleep on a condition variable, the thread will be removed from the runqueue until the condition variable has been signaled.

-------------------

You should use Windows synchronization events for this, so your thread is doing nothing while waiting. See MSDN for more info; I'd start with CreateEvent(), and then go to the rest of the Event-related functions here for OpenEvent(), PulseEvent(), SetEvent() and ResetEvent().

And, of course, WaitForSingleObject() or WaitForMultipleObjects(), as pointed out by mrduclaw in the comment below.

-------------------

Lacking the more preferred options already given, I generally just yield the CPU in a loop until the desired condition is met.

-------------------

Basically, you have two possibilities for your N+1th thread.

  • If its work is rare, the best thing to do is simply to ask it to sleep, and wake it up on demand. Rare context switches are insignificants.
  • If it has to work often, then you may need to spinlock it, that is, a busy waiting state that prevent it from being rescheduled, or switched.
-------------------

Each global variable should have an accompanying event for your N+1 thread. Whenever you change the status of the global variable, set the event to the signaled state. It is better to hide these variables inside a singleton-class private properties and expose functions to get and set the values. The function that sets the value will do the comparison and will set the events if needed. So, your N+1 thread will just to the loop of WaitForMultipleObjects with infinite timeout. Another global variable should be used to signal that the application as a whole exits, so the threads will be able to exit. You may only exit your application after your last thread has finished. So, if you need to prematurely exit, you have to notify all your threads that they have to exit. Those threads that are permanently running, can be notified by just reading a variable periodically. Those that are waiting, like the N+1 thread, should be notified by an event.

People have suggested to use CreateEvent (to create auto-reset events), SetEvent and WaitForMultipleObjects. I agree with them. Other people have suggested, in addition to the above functions, to use ResetEvent and PulseEvent. I do not agree with them. You don’t need ResetEvent with auto-reset events. This is the function supposed to be used with manual-reset events, but the application of the manual-reset events is very limited, you will see below.

자동 재설정 이벤트를 생성하려면 bManualReset 매개 변수를 FALSE로 설정하여 CreateEvent Win32 API 함수를 호출합니다 (참인 경우 함수는 ResetEvent 함수를 사용하여 이벤트 상태를 설정해야하는 수동 재설정 이벤트 객체를 생성합니다). 신호 없음 – 이것은 필요한 것이 아님). 이 매개 변수가 FALSE이면 함수는 자동 재설정 이벤트 객체를 생성하고 시스템은 대기중인 단일 스레드가 해제 된 후 즉, WaitForMultipleObjects 또는 WaitForSigleObject와 같은 함수에서 종료 된 후 이벤트 상태를 신호 없음으로 자동 재설정합니다. 이전에 썼지 만 모두가 아닌 하나의 스레드 만 알림을받을 것이므로 대기중인 각 스레드에 대해 하나의 이벤트가 필요합니다. 대기 할 스레드가 하나만있을 것이므로 이벤트가 하나만 필요합니다.

PulseEvent에 대해 – 신뢰할 수 없으며 사용해서는 안됩니다. https://msdn.microsoft.com/en-us/library/windows/desktop/ms684914(v=vs.85).aspx를 참조 하십시오. PulseEvent가 호출되는 순간 "대기"상태에있는 스레드 만 PulseEvent에 의해 통지됩니다. 다른 상태에 있으면 알림이 전송되지 않으며 스레드 상태가 무엇인지 절대 알 수 없습니다. 동기화 개체에서 대기중인 스레드는 커널 모드 비동기 프로 시저 호출에 의해 대기 상태에서 일시적으로 제거 된 다음 APC가 완료된 후 대기 상태로 돌아갈 수 있습니다. 스레드가 대기 상태에서 제거 된 시간 동안 PulseEvent에 대한 호출이 발생하면 PulseEvent는 호출 된 순간에 대기중인 스레드 만 해제하므로 스레드가 해제되지 않습니다. 다음 링크에서 커널 모드 APC (Asynchronous Procedure Call)에 대해 자세히 알아볼 수 있습니다.-https://msdn.microsoft.com/en-us/library/windows/desktop/ms681951(v=vs.85).aspx - http://www.drdobbs.com/inside-nts-asynchronous-procedure-call / 184416590 - http : //www.osronline.com/article.cfm ? id=75 다음 기사에서 자동 재설정 이벤트 및 수동 재설정 이벤트에 대한 더 많은 아이디어를 얻을 수 있습니다.- https : //www.codeproject.com/ 기사 / 39040 / 자동 및 수동 재설정 이벤트-재검토

수동 재설정 이벤트에 관해서도 특정 조건 및 특정 경우에 사용할 수 있습니다. 응용 프로그램 종료와 같이 한 번만 발생하는 전역 상태 변경의 여러 인스턴스를 알려야 할 때 안정적으로 사용할 수 있습니다.

대기중인 스레드가 하나 뿐이지 만 나중에 대기중인 스레드가 더 많아 질 수 있으므로이 정보가 유용 할 것입니다.

자동 재설정 이벤트는 하나의 스레드를 알리는 데만 사용할 수 있습니다 (자동 재설정 이벤트를 위해 더 많은 스레드가 동시에 대기하고 이벤트를 설정 한 경우 하나의 스레드 만 종료되고 재설정되며 다른 스레드의 동작은 정의되지 않음). . Microsoft 문서에서 우리는 하나의 스레드 만 종료되고 다른 스레드는 종료되지 않는다고 가정 할 수 있습니다. 이것은 명확하지 않습니다. 그러나 다음 인용문을 고려해야합니다.“선입 선출 (FIFO) 순서를 가정하지 마십시오. - 같은 커널 모드 장갑차 같은 외부 이벤트는 대기 순서 "소스 변경할 수 있습니다 https://msdn.microsoft.com/en-us/library/windows/desktop/ms682655(v=vs.85).aspx을

따라서 모든 스레드에 매우 빠르게 알려야하는 경우 각 스레드에 대해 각 자동 재설정 이벤트를 알리는 대신 수동 재설정 이벤트를 신호 된 상태 (SetEvent를 호출하여)로 설정하면됩니다. 수동 재설정 이벤트를 알리면 그 이후로 ResetEvent를 호출하지 마십시오.

댓글
공지사항
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31