【发布时间】:2010-01-10 17:42:11
【问题描述】:
我正在尝试为我的 FileWatcher 类编写单元测试。
FileWatcher 派生自 Thread 类并使用 WaitForMultipleObjects 在其线程过程中等待两个句柄:
- 从
FindFirstChangeNotification返回的句柄 - 允许我取消上述等待的事件句柄。
所以基本上FileWatcher 正在等待先发生的事情:文件更改或我告诉它停止观看。
现在,当尝试编写测试此类的代码时,我需要等待它开始等待。
Peusdo 代码:
FileWatcher.Wait(INFINITE)
ChangeFile()
// Verify that FileWatcher works (with some other event - unimportant...)
问题是存在竞争条件。我需要首先确保 FileWatcher 已经开始等待(即它的线程现在在 WaitForMultipleObjects 上被阻塞),然后才能触发第 2 行中的文件更改。我不想使用 Sleeps,因为它看起来很笨拙,并且在调试时肯定会给我带来问题。
我熟悉SignalObjectAndWait,但它并不能真正解决我的问题,因为我需要它来“SignalObjectAndWaitOnMultipleObjects”...
有什么想法吗?
编辑
为了澄清一点,这里是FileWatcher 类的简化版本:
// Inherit from this class, override OnChange, and call Start() to turn on monitoring.
class FileChangeWatcher : public Utils::Thread
{
public:
// File must exist before constructing this instance
FileChangeWatcher(const std::string& filename);
virtual int Run();
virtual void OnChange() = 0;
};
它继承自Thread并实现线程函数,看起来像这样(非常简化):
_changeEvent = ::FindFirstChangeNotificationW(wfn.c_str(), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
HANDLE events[2] = { _changeEvent, m_hStopEvent };
DWORD hWaitDone = WAIT_OBJECT_0;
while (hWaitDone == WAIT_OBJECT_0)
{
hWaitDone = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);
if (hWaitDone == WAIT_OBJECT_0)
OnChange();
else
return Thread::THREAD_ABORTED;
}
return THREAD_FINISHED;
请注意,线程函数等待两个句柄,一个 - 更改通知,另一个 - “停止线程”事件(继承自 Thread)。
现在测试这个类的代码如下所示:
class TestFileWatcher : public FileChangeWatcher
{
public:
bool Changed;
Event evtDone;
TestFileWatcher(const std::string& fname) : FileChangeWatcher(fname) { Changed = false; }
virtual void OnChange()
{
Changed = true;
evtDone.Set();
}
};
And 从 CPPUnit 测试中调用:
std::string tempFile = TempFilePath();
StringToFile("Hello, file", tempFile);
TestFileWatcher tfw(tempFile);
tfw.Start();
::Sleep(100); // Ugly, but we have to wait for monitor to kick in in worker thread
StringToFile("Modify me", tempFile);
tfw.evtDone.Wait(INFINITE);
CPPUNIT_ASSERT(tfw.Changed);
这个想法是摆脱中间的睡眠。
【问题讨论】:
标签: c++ windows multithreading