Win 7,x64,Visual Studio Community 2015,C ++
我有一个我需要暂停/取消暂停或终止的线程,我目前使用手动重置"运行"或者"杀死"事件。线程中的循环每次暂停5000ms。
我的目标是能够在等待的中途停止等待或终止线程。
问题是我目前的设置方式,我需要在"运行"事件进入非信号状态,但没有办法做到这一点,除非我创建一个极性反转的事件,但这似乎是一个kludge。简而言之,我需要一个电平敏感信号,而不是边缘敏感信号。
也许事件应该只是切换运行状态?
这是线程函数:
DWORD WINAPI DAQ::_fakeOutFn(void *param) {
DAQ *pThis = (DAQ *)param;
const DWORD timeout = 5000;
bool running = false;
HANDLE handles[] = { pThis->hFakeTaskRunningEvent, pThis->hFakeTaskKillEvent };
do {
DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
switch (result) {
case WAIT_OBJECT_0: // Run started or continued
running = true;
pThis->outputIndex++;
if (pThis->outputIndex >= pThis->numSamples)
pThis->outputIndex = 0;
// Wait here
// Not sure how to cancel this if the TaskRunningEvent goes false during the wait
DWORD result2 = WaitForMultipleObjects(2, handles, FALSE, timeout);
// Check result2, and 'continue' the loop if hFakeTaskRunningEvent went to NON-SIGNALLED state
break;
case WAIT_OBJECT_0 + 1: // Kill requested
running = false;
break;
default:
_ASSERT_EXPR(FALSE, L"Wait error");
break;
}
} while (running);
return 0;
}
答案 0 :(得分:0)
为运行和恢复状态使用单独的事件。然后,您可以重置resume事件以暂停,并发出恢复事件的信号。应该使用running事件让线程知道什么时候有工作要做,而不是什么时候应该暂停该工作一段时间。
DWORD WINAPI DAQ::_fakeOutFn(void *param)
{
DAQ *pThis = (DAQ *)param;
bool running = false;
HANDLE handles[] = { pThis->hFakeTaskRunningEvent, pThis->hFakeTaskKillEvent };
do
{
DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
switch (result)
{
case WAIT_OBJECT_0: // Run started
{
running = true;
pThis->outputIndex++;
if (pThis->outputIndex >= pThis->numSamples)
pThis->outputIndex = 0;
// check for pause here
HANDLE handles2[] = { pThis->hFakeTaskResumeEvent, pThis->hFakeTaskKillEvent };
DWORD result2 = WaitForMultipleObjects(2, handles2, FALSE, INFINITE);
switch (result2)
{
case WAIT_OBJECT_0;
break;
case WAIT_OBJECT_0 + 1: // Kill requested
running = false;
break;
default:
_ASSERT_EXPR(FALSE, L"Wait error");
break;
}
if (!running) break;
// continue working...
break;
}
case WAIT_OBJECT_0 + 1: // Kill requested
running = false;
break;
default:
_ASSERT_EXPR(FALSE, L"Wait error");
break;
}
}
while (running);
return 0;
}
答案 1 :(得分:0)
这里我不使用事件,而是使用'command'(运行,暂停,退出)将Apc队列到此线程。但需要了解更多关于任务的信息,以获得最佳解决方案你在写服务吗?
struct DAQ
{
HANDLE _hEvent;
enum STATE {
running,
paused,
exit
} _state;
DAQ()
{
_hEvent = 0;
}
~DAQ()
{
if (_hEvent)
{
ZwClose(_hEvent);
}
}
NTSTATUS Init()
{
return ZwCreateEvent(&_hEvent, EVENT_ALL_ACCESS, 0, NotificationEvent, FALSE);
}
void Close()
{
if (HANDLE hEvent = InterlockedExchangePointer(&_hEvent, 0))
{
ZwClose(hEvent);
}
}
DWORD fakeOutFn()
{
DbgPrint("running\n");
_state = running;
ZwSetEvent(_hEvent, 0);
static LARGE_INTEGER Interval = { 0, MINLONG };
do ; while (0 <= ZwDelayExecution(TRUE, &Interval) && _state != exit);
DbgPrint("exit\n");
return 0;
}
static DWORD WINAPI _fakeOutFn(PVOID pThis)
{
return ((DAQ*)pThis)->fakeOutFn();
}
void OnApc(STATE state)
{
_state = state;
static PCSTR stateName[] = { "running", "paused" };
if (state < RTL_NUMBER_OF(stateName))
{
DbgPrint("%s\n", stateName[state]);
}
}
static void WINAPI _OnApc(PVOID pThis, PVOID state, PVOID)
{
((DAQ*)pThis)->OnApc((STATE)(ULONG_PTR)state);
}
};
void test()
{
DAQ d;
if (0 <= d.Init())
{
if (HANDLE hThread = CreateThread(0, 0, DAQ::_fakeOutFn, &d, 0, 0))
{
if (STATUS_SUCCESS == ZwWaitForSingleObject(d._hEvent, FALSE, 0))// need for not QueueApc too early. in case ServiceMain this event not need
{
d.Close();
int n = 5;
do
{
DAQ::STATE state;
if (--n)
{
state = (n & 1) != 0 ? DAQ::running : DAQ::paused;
}
else
{
state = DAQ::exit;
}
ZwQueueApcThread(hThread, DAQ::_OnApc, &d, (PVOID)state, 0);
} while (n);
}
ZwWaitForSingleObject(hThread, FALSE, 0);
ZwClose(hThread);
}
}
}