Myślę, że to może załatwić sprawę. Wylicz klasę Event i przeciąż funkcję Process().
#include <process.h> // Along with all the normal windows includes
//*********************************************
using namespace os;
Mutex globalQueueMutex;
class QueueReader : public Event
{
public:
virtual void Process()
{
// Lock the queue
Locker l(globalQueueMutex);
// pop data off
// process data
return; // queue will automatically unlock
}
};
QueueReader myQueueReader;
//*********************************************
// The queue writer would have functions like :
void StartQueueReader()
{
Thread(QueueReader::StartEventHandler, &myQueueReader);
}
void WriteToQueue()
{
Locker l(globalQueueMutex);
// write to the queue
myQueueReader.SignalProcess(); // tell reader to wake up
}
// When want to shutdown
void Shutdown()
{
myQueueReader.SignalShutdown();
}
Oto klasy, które wykonują magię.
namespace os {
// **********************************************************************
/// Windows implementation to spawn a thread.
static uintptr_t Thread (void (*StartAddress)(void *), void *ArgList)
{
return _beginthread(StartAddress, 0, ArgList);
}
// **********************************************************************
/// Windows implementation of a critical section.
class Mutex
{
public:
// Initialize section on construction
Mutex() { InitializeCriticalSection(&cs_); }
// Delete section on destruction
~Mutex() { DeleteCriticalSection(&cs_); }
// Lock it
void lock() { EnterCriticalSection(&cs_); }
// Unlock it
void unlock() { LeaveCriticalSection(&cs_); }
private:
CRITICAL_SECTION cs_;
}; // class Mutex
/// Locks/Unlocks a mutex
class Locker
{
public:
// Lock the mutex on construction
Locker(Mutex& mutex): mutex_(mutex) { mutex_.lock(); }
// Unlock on destruction
~Locker() { mutex_.unlock(); }
private:
Mutex& mutex_;
}; // class Locker
// **********************************************************************
// Windows implementation of event handler
#define ProcessEvent hEvents[0]
#define SetTimerEvent hEvents[1]
#define ShutdownEvent hEvents[2]
/// Windows implementation of events
class Event
{
/// Flag set when shutdown is complete
bool Shutdown;
/// Max time to wait for events
DWORD Timer;
/// The three events - process, reset timer, and shutdown
HANDLE hEvents[3];
public:
/// Timeout is disabled by default and Events assigned
Event(DWORD timer = INFINITE) : Timer(timer)
{
Shutdown = false;
ProcessEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
SetTimerEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
ShutdownEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
}
/// Close the event handles
virtual ~Event()
{
CloseHandle(ProcessEvent);
CloseHandle(SetTimerEvent);
CloseHandle(ShutdownEvent);
}
/// os::Thread calls this to start the Event handler
static void StartEventHandler(void *pMyInstance)
{ ((Event *)pMyInstance)->EventHandler(); }
/// Call here to Change/Reset the timeout timer
void ResetTimer(DWORD timer) { Timer = timer; SetEvent(SetTimerEvent); }
/// Set the signal to shutdown the worker thread processing events
void SignalShutdown() { SetEvent(ShutdownEvent); while (!Shutdown) Sleep(30);}
/// Set the signal to run the process
void SignalProcess() { SetEvent(ProcessEvent); }
protected:
/// Overload in derived class to process events with worker thread
virtual void Process(){}
/// Override to process timeout- return true to terminate thread
virtual bool Timeout(){ return true;}
/// Monitor thread events
void EventHandler()
{
DWORD WaitEvents;
while (!Shutdown)
{
// Wait here, looking to be signaled what to do next
WaitEvents = WaitForMultipleObjects(3, hEvents, FALSE, Timer);
switch (WaitEvents)
{
// Process event - process event then reset for the next one
case WAIT_OBJECT_0 + 0:
Process();
ResetEvent(ProcessEvent);
break;
// Change timer event - see ResetTimer(DWORD timer)
case WAIT_OBJECT_0 + 1:
ResetEvent(SetTimerEvent);
continue;
// Shutdown requested so exit this thread
case WAIT_OBJECT_0 + 2:
Shutdown = true;
break;
// Timed out waiting for an event
case WAIT_TIMEOUT:
Shutdown = Timeout();
break;
// Failed - should never happen
case WAIT_FAILED:
break;
default:
break;
}
}
}
};
} // namespace os
Wolałbym, aby zdarzenia znajdowały się poza klasą i wewnątrz funkcji punktu wejścia wątku. Powodem jest drugie wydarzenie, na które wątki również czekają. To jest, gdy użytkownik chce zakończyć program, a tym samym zakończyć nieskończoną pętlę while. Kiedy tak się stanie, użytkownik wyśle polecenie zamknięcia programu, wątek push przestanie nasłuchiwać danych i zamknie się, a wątek pchania przestanie czekać na to, że wątek będzie zawierał dane, a także zamknie się. – rossb83
Możesz zrobić to samo ze zdarzeniami zewnętrznymi. Zaktualizowałem powyższą odpowiedź. – Werolik
czy nie miałeś na myśli, aby wątek1 wywoływał reset, a wątek 2 wywoływał zestaw w zewnętrznej wersji? Ponadto, Jak uniknąć impasu w tym scenariuszu: 1. wątek1 nie uda się pop. 2. zestaw wywołań thread2. 3. Resetowanie wątku1. – Nir