代码之家  ›  专栏  ›  技术社区  ›  Assaf Lavie

正在等待WaitForMultipleObjects

  •  2
  • Assaf Lavie  · 技术社区  · 15 年前

    我正在尝试为我的 FileWatcher 班级。

    文件观察员 从线程类派生并使用 WaitForMultipleObjects 要在其线程过程中等待两个句柄,请执行以下操作:

    1. 句柄从返回 FindFirstChangeNotification
    2. 事件的句柄,它允许我取消上述等待。

    所以基本上 文件观察员 正在等待最先发生的事情:文件更改或我告诉它停止监视。

    现在,当尝试编写测试这个类的代码时,我需要等待它开始等待。

    Peusdo Code:

    FileWatcher.Wait(INFINITE)
    ChangeFile()
    // Verify that FileWatcher works (with some other event - unimportant...)
    

    问题是有一个比赛条件。我需要首先确保filewatcher已经开始等待(即它的线程现在被阻塞在 WaitForMultipleObjects )在第2行触发文件更改之前。我不想使用sleeps,因为,嗯,它看起来很糟糕,在调试时一定会给我带来问题。

    我很熟悉 SignalObjectAndWait 但它并不能真正解决我的问题,因为我需要它来“信号对象和等待多个对象”…

    有什么想法吗?


    编辑

    为了澄清一点,这里是 文件观察员 班级:

    // 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函数等待两个句柄,一个是更改通知,另一个是“stop 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();
        }
    };
    

    并从CPP单元测试中调用:

    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);
    

    我们的想法是摆脱中间的睡眠。

    4 回复  |  直到 15 年前
        1
  •  3
  •   avakar    15 年前

    没有比赛,你不必等待 FileWatcher 进入 WaitForMultipleObjects . 如果在调用函数之前执行更改,它将立即返回。

    编辑: 我现在可以看比赛了。你为什么不把下一行移一下呢

    _changeEvent = ::FindFirstChangeNotificationW(/*...*/);
    

    从线程函数到的构造函数 FileChangeWatcher ?这样,你就可以确定 StringToFile 调用了函数,文件已被监视。

        2
  •  1
  •   Len Holgate    15 年前

    你应该打电话 FindFirstChangeNotification() 在观察程序的构造函数中,存储它返回的句柄,以便在线程函数中使用。这意味着从施工开始,您将看到变化事件。

    一旦线程启动,它只需调用两个句柄等待。如果在线程启动之前发生了更改,则 查找第一个更改通知() 已返回将被发出信号,并将处理更改。如果您希望线程监视许多更改,那么它应该循环并调用 FindNextChangeNotification() 在处理每个通知之后。

        3
  •  0
  •   Partial    15 年前

    相反,你可以使用互斥体吗?在一个线程能够访问其所需的资源之前,它必须锁定互斥体,并为其他需要该资源的线程解锁互斥体。

        4
  •  0
  •   John Dibling    15 年前

    调用CreateEvent()创建非信号事件。当观察线程进入其主循环(或其他)时,setEvent()。同时,在FileWatcher中,首先在事件上等待singleObject(),然后在返回后,像以前那样等待wfmo。

    推荐文章