【问题标题】:Do I need to synchronize access to a HANDLE on Windows?我需要在 Windows 上同步对 HANDLE 的访问吗?
【发布时间】:2015-11-14 22:43:54
【问题描述】:

我有一个 waitable timer 的句柄,可以在我的 Windows 服务中的许多正在运行的线程之间共享,用于 API,例如 CreateWaitableTimerWaitForSingleObjectSetWaitableTimerCancelWaitableTimer

我的问题是,我是否需要通过互斥锁或临界区同步访问(读/写)这个 HANDLE 本身?

编辑: 好的,我想我需要澄清一下(用代码):

//Say, I have a global handle
HANDLE ghWaitableTimer = NULL;      //Originally set to NULL

...

//Thread one
if(!ghWaitableTimer)
{
    ghWaitableTimer = ::CreateWaitableTimer(NULL, FALSE, NULL);
}

...

//Thread two
if(ghWaitableTimer)
{
    ::SetWaitableTimer(ghWaitableTimer, &liWhen, 0, NULL, NULL, FALSE);
}

...

//Thread three
if(ghWaitableTimer)
{
    ::WaitForSingleObject(ghWaitableTimer, INFINITE);
}

或者我需要这样做:

//Say, I have a global handle
HANDLE ghWaitableTimer = NULL;      //Originally set to NULL
CRITICAL_SECTION CriticalSection;   //Must be initialized before it's used

...

//Thread one
::EnterCriticalSection(&CriticalSection);

if(!ghWaitableTimer)
{
    ghWaitableTimer = ::CreateWaitableTimer(NULL, FALSE, NULL);
}

::LeaveCriticalSection(&CriticalSection);

...

//Thread two
::EnterCriticalSection(&CriticalSection);
HANDLE hTimer = ghWaitableTimer;
::LeaveCriticalSection(&CriticalSection);

if(hTimer)
{
    ::SetWaitableTimer(hTimer, &liWhen, 0, NULL, NULL, FALSE);
}

...

//Thread three
::EnterCriticalSection(&CriticalSection);
HANDLE hTimer = ghWaitableTimer;
::LeaveCriticalSection(&CriticalSection);

if(hTimer)
{
    ::WaitForSingleObject(hTimer, INFINITE);
}

【问题讨论】:

  • 无论你在做什么,它听起来'关闭':(
  • @MartinJames 为什么?我在这里没有看到问题(除了不必要担心同步同步,这是问题)
  • @deviantfan 好吧,我不确定。我一直在努力思考一些需要多个线程在同一个计时器上等待的要求。我想不出一个。也许只是我:)
  • 我的意思是,事件有很多问题;如果多个线程在一个 MRE 上等待,它会被设置,然后立即被一个正在等待的线程重置,任何其他正在等待但没有从准备好运行的线程,在没有实际运行的情况下再次设置回等待全部。所以,我有点担心这同样适用于定时器——也许如果一个线程被设置为运行并重新启动定时器等待,其他一些正在等待的线程可能不会运行......?
  • 如果我有这样的要求,我会让一个线程在计时器上等待并发出一个单独的同步信号(事件或信号量)。对于每个其他等待线程。

标签: c++ c windows winapi thread-synchronization


【解决方案1】:

如果变量的值可能发生变化,您只需要同步从多个线程读取全局变量。如果您正在创建单个计时器对象并且句柄的值在此之后不再更改,则不需要同步来读取它的值。

【讨论】:

    【解决方案2】:

    使用可等待计时器,即。在给定定时器句柄的情况下启动定时器并等待使用该句柄触发,不需要互斥锁等支持。

    从描述中可以清楚地看出它是专门为线程间操作而设计的,例如。另一个线程可以使用WaitForSingleObject来等待触发定时器事件等。
    如果有必要使用互斥锁来保护它,上面提到的用例
    甚至根本不可能,而是需要轮询。

    如果这还不够推理,这里是页面的第一句Synchronization Objects

    同步对象是一个对象,其句柄可以在 协调多个执行的等待函数之一 线程。

    ...和提到的页面的子类别是例如。互斥体、信号量、
    等待计时器;一切都在同一水平上。

    不过,我刚才所说的,只对使用有效,如第一句所述。这些操作的共同点是您已经有一个计时器句柄(所述操作不会更改)。 创建一个新的计时器句柄并将其分配给一个变量确实会改变变量值...

    所以,你基本上有两个问题:
    1) 如果线程 2 在线程 1 创建计时器之前启动计时器,您认为会发生什么?如果在启动 Visual Studio 之前在 Visual Studio 中键入一些文本会发生什么?对。
    2)句柄只是一个数字ID,可以随意复制和移动。即使在创建之后,计时器也无法保护它自己的句柄。在使用过程中对手柄进行任何更改都是不好的。

    为此,互斥锁也不是解决方案。它可以保护计时器句柄,但谁来保护互斥体句柄......?对。任何同步机制都依赖于用于同步任何东西之前做好准备。

    真正解决您的问题的方法是创建计时器并将其分配给一个句柄在开始任何线程之前;然后提供启动线程的句柄(参数或全局变量等)

    【讨论】:

    • @c00000fd 查看编辑(第一句和“但是”之后的部分)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多