【问题标题】:Atomic Operation C++原子操作 C++
【发布时间】:2009-11-05 12:59:21
【问题描述】:

在 Windows 平台的 C++ 中,我想以原子方式执行一组函数调用,以便执行不会切换到我进程中的其他线程。我该怎么做呢?有什么想法、提示吗?

编辑:我有一段代码:

someObject->Restart();

WaitForSingleObject(handle, INFINITE);

现在 Restart() 函数以异步方式完成其工作,因此它会快速返回,并且当某个对象重新启动时,它会从另一个线程向我发送一个事件,在该线程中我会发出我正在处理的事件句柄的信号等待并因此继续处理。但是现在的问题是,在代码到达 WaitForSingleObject() 部分之前,我收到了重新启动完成事件并发出了该事件的信号,之后 WaitForSingleObject() 就再也没有返回了不再发出信号。这就是为什么我想将 Restart()WaitForSingleObject() 作为原子执行。

【问题讨论】:

  • 问题是:你为什么要这么做?如果您试图通过禁止内核切换线程来“同步”对数据结构的访问,那么您的处理方式非常错误。所以请解释你为什么要这样做。
  • 即使你能做到这一点,它也会在一个会同时执行多个线程的多核系统上中断
  • 你的手柄信号如何? PulseEvent()SetEvent()?
  • 我用 SetEvent() 发出信号

标签: c++ windows multithreading


【解决方案1】:

这通常是不可能的。您不能强制操作系统不切换到其他线程。
您可以执行以下操作之一:

  • 使用锁、互斥锁、临界区或信号量来同步少数几个接触相同数据的线程。
  • 使用诸如InterlockedIncrement()InterlockedCompareExchange()等win32 api调用形式的原子基本操作,例如比较和交换或原子添加

【讨论】:

    【解决方案2】:

    您不希望所有线程都等待,您只想等待新线程完成,而不会有丢失信号的风险。这可以使用信号量来完成。

    使用 CreateSemaphore(NULL,0,1,NULL) 创建此代码和 Restart 最终执行的代码都知道的信号量。 在您显示的代码中,您仍将使用 WaitforSingleObject 来等待您的信号量。当执行 Release 代码的线程完成它的工作后,让它调用 ReleaseSemaphore。

    如果先调用 ReleaseSemaphore,WaitforSingleObject 会让你立即通过。如果先调用W​​aitforSingleObject,会等待ReleaseSemaphore。

    MSDN 应该也能帮到你。

    【讨论】:

      【解决方案3】:

      失败事件竞赛的一般解决方案是计数信号量。

      【讨论】:

        【解决方案4】:

        您是否在使用PulseEvent() 来表示您的句柄?如果是这样,那就是问题所在。

        根据MSDN

        如果没有线程在等待,或者如果没有 线程可以立即释放, PulseEvent 只是设置事件 对象的状态为非信号和 返回。

        因此,如果句柄在您等待之前发出信号,则句柄会立即被PulseEvent() 置于非信号状态。这似乎就是您“错过”该活动的原因。要更正此问题,请将 PulseEvent() 替换为 SetEvent()

        但是,在这种情况下,您可能需要在等待完成后重置事件。这当然取决于此代码是否在应用程序的生命周期内多次执行。假设您的等待线程是 only 在句柄上等待的线程,请使用 CreateEvent() 创建自动重置事件。这将在您的等待线程释放后自动重置句柄,使其在下一次通过时自动可用。

        【讨论】:

          【解决方案5】:

          好吧,你可以暂停(使用SuspendThread)进程中的所有其他线程,但我想你应该重新考虑你的程序设计。

          【讨论】:

          • SuspendThread 被许多人认为是狡猾的行为,他们认为只有 Debuggers 和 Garbage Collectors 实现应该暂停线程。
          【解决方案6】:

          这很容易解决。只要确保事件是自动重置事件(参见 CreateEvent 的参数),并且只调用 SetEvent 到事件句柄,永远不要调用 ResetEvent 或 PulseEvent 或其他一些东西。所以 WaitForSingleObject 总是会正确返回。如果事件已经设置,WaitForSingleObject 将立即返回并重置事件。

          【讨论】:

            【解决方案7】:

            虽然我总体上担心您的设计(即您将并发任务按顺序进行,因此失去了使其并发的所有辛勤工作的好处),但我认为我看到了简单的解决方案。

            将您的事件句柄更改为 MANUAL RESET 而不是 AUTORESET。 (参见 CreateEvent)。

            这样你就不会错过信号。 在 WaitForSingleObject(...) 之后,调用 ResetEvent()。

            编辑: 忘记我刚才说的话。那是行不通的。请参阅下面的 cmets。

            【讨论】:

            • 这不会解决问题。如果他已经在使用自动重置事件,则该事件将保持信号状态,直到等待线程被释放。如果没有等待线程,则事件保持信号状态,直到有一个。此时,线程立即被释放,事件被重置。请参阅有关 CreateEvent 的 MSDN 文档:msdn.microsoft.com/en-us/library/ms682396(VS.85).aspx
            • 哦,你说得对。我忘了。所以他一定是做错了什么。要么其他线程也在等待对象,要么他正在使用损坏的 PulseEvent 或其他东西。
            • 自动重置事件非常可靠,如果您只需要通知一个线程。无需将自动重置事件更改为手动重置事件。
            猜你喜欢
            • 2017-11-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-01-10
            • 2023-03-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多