如何向多个线程发出事件信号

发布于 12-10 22:22 字数 699 浏览 0 评论 0原文

如何将事件发送到应用程序的多个正在运行的线程?

例如:我的主线程想要向所有正在运行的线程发出应用程序将退出的信号。

我有点困惑这些可能性中的哪一种会带来简单可靠的解决方案:

  • condition_variablenotify_all from boost
  • CONDITION_VARIABLE code> 和来自 WinApi 的 WakeAllConditionsVariable
  • CEvent 来自 WinApi,
  • 在线程上使用 mutextry_lock
  • 来自 boostsignalslots
  • ,甚至是带有 CriticalSection 的全局变量,用于保护 getter/setter
  • 在此处插入您的解决方案...

您能否为初学者指明正确的方向,并且也许可以对我提供的上述可能性进行一些说明。

补充: - 操作系统是Windows XP

How can I send an event to several running threads of my application?

For example: My main thread wants to signal all running threads that the application will exit.

I'm a little confused which of those possibilities leads to an easy and reliable solution:

  • condition_variable with notify_all from boost
  • CONDITION_VARIABLE with WakeAllConditionsVariable from WinApi
  • CEvent from WinApi
  • using a mutex and try_lock on the threads
  • signal and slots from boost
  • or even a global variable with a CriticalSection for protection of getter/setters
  • insert your solution here...

Could you point a beginner into the right direction and perhaps loose some words about the possiblities above I provided.

Added: - OS is Windows XP

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

黑色毁心梦2024-12-17 22:22:00

如果您想“向所有正在运行的线程发出应用程序将退出的信号”,则手动重置甚至可以解决问题。

您需要让每个线程偶尔检查事件,如果事件已发出信号则退出。

然后,您只需发出事件信号并等待线程完成(如果需要)。

如果您需要多次执行此操作,则情况会更复杂,因为必须手动重置手动重置事件,并且您需要更多代码来确保在重置事件以在后续通知中使用之前每个线程都已收到通知,但是鉴于你的问题,这会很好地工作。

Given you want to "signal all running threads that the application will exit" a manual reset even would do the trick.

You need to have each thread check the event occasionally and exit if the event has been signalled.

You then simply signal the event and wait for the threads to complete if you need to.

It's more complex if you need to do this more than once as a manual reset event must be reset manually and you'd need more code to make sure that every thread has received the notification before you reset the event for use in subsequent notifications, but given your question, this will work just fine.

公布2024-12-17 22:22:00

你在这里有两个不同的问题。第一个是如何使代码的不同部分可以使用一点数据,以便不同的线程可以读取它,而第二个是如何以线程安全的方式修改一点状态,以便线程可以读取它。采取行动。

要使一些数据可供不同的线程使用,您可以使用不同的方法:

  • 如果您有对管理线程的对象的引用,您可以使用它们来手动遍历线程列表并通知每个线程
  • 您可以使用 boost::在程序中的某个时刻发出信号来管理这些引用(即创建一个 exit 信号,并在构造时连接所有线程。
  • 如果您没有这些引用,则可以设置 exit< /code> 标记为全局变量并让线程从中读取

I倾向于选择每个线程由单个对象管理,在这种情况下,我会尝试将数据位移动到该管理器并避免全局。不需要信号机制,因为您可以遍历这些依赖项。

问题的第二部分是如何以线程安全的方式将数据从主线程传递到其余线程,在这种特殊情况下,一位数据在程序的大部分时间里只有一个值,并且被设置为在某一点有不同的固定值。这是全局变量还是线程管理器状态的一部分并不重要:

  • 互斥体。每个线程在读/写之前锁定,确保修改是安全的
  • 原子操作。对于足够小的数据类型,线程库/操作系统提供原子操作,这些操作将添加适当的内存屏障,以确保数据跨区域移动。

结合您拥有的全局变量或局部变量,将直接修改(全局变量) )或通过从主线程触发的函数调用,直接或通过某种信号机制。标志的修改必须通过原子操作(引入内存栅栏)或通过持有互斥体来完成。

如果线程可以处于非活动状态(等待条件变量),那么您可能希望避免全局、调用函数、锁定互斥体以及互斥体内部都更改标志并使用条件变量来唤醒等待线程。等待线程在从某种条件下等待返回时将负责检查该标志。

You have two different problems here. The first one is how to make a bit of data available to different parts of the code, so that the different threads can read it, while the second one is how to modify a bit of state in a thread safe way so that the threads can act on it.

To make a bit of data available to the different threads you can use different approaches:

  • If you have references to the objects that manage the threads, you can use those to manually walk the list of threads and notify each one
  • You could use boost::signal at some point in the program to manage those references (i.e. create an exit signal, and connect all threads on construction.
  • If you don't have those references, you can set the exit flag as a global variable and have the threads read from it

I tend to prefer each thread to be managed by a single object, in which case I would try to move the bit of data to that manager and avoid the global. In most cases the design establishes dependencies and ownership of the resources, in which case you would not need the signals mechanism, as you can walk those dependencies.

The second part of the problem is how to, in a thread safe way, pass the data from the main thread to the rest of the threads, and in this particular case a single bit of data that has one value during most of the program and is set to a different fixed value at one point. Whether this is a global variable or part of the state of the thread manager does not really matter:

  • Mutex. Each thread locks before reading/writing ensuring that the modifications are safe
  • Atomic operations. For a small enough data type, the threading library/OS offers atomic operations that will add the appropriate memory barriers to ensure the data is moved across

Combining both what you have is either a global or a local variable that will be modified either directly (global) or through function calls triggered from the main thread, either directly or through some signals mechanism. The modification of the flag must be done either with atomic operations (introducing memory fences) or by holding a mutex.

If the threads can be inactive (waiting on a condition variable), then you probably want to avoid the global, call the functions, lock on the mutex and inside the mutex both change the flag and use the condition variables to wake the waiting thread. The waiting thread would be responsible for checking the flag whenever it comes back from waiting in a condition.

归途2024-12-17 22:22:00

如果您只是测试简单的状态更改(何时退出),则条件变量就足够了。 只要确保找到一个好的 WinAPI 示例即可:您几乎肯定需要多次测试状态(与您的直觉可能告诉您的不同)。

如果您打算在线程之间共享任务/事件,好的模式是使用基于互斥队列和条件变量的生产者-消费者模式。一个典型的例子是,您有一个生产者线程,它生成的作业被推送到队列中(例如,每个任务将数据写入不同的文件)。然后,您可以拥有多个消费者线程,它们将从队列中删除任务并对其执行操作。要在线程之间进行通信,您可以使用一个条件变量,该变量将向使用者线程发出信号:互斥队列可能为空。 (阅读条件变量以了解为什么我在这里说“可能”)。

随着您进行越来越多的线程编程,您将寻找不需要互斥体的机会。例如,如果我在磁盘上有大量只读数据,并且我希望您的线程根据这些数据进行计算,您可以在生成线程之前读取数据。然后,所有线程都可以访问这些数据,而无需使用锁,只要它们正常运行并且不写入数据即可。您会发现仅使用互斥体和条件变量即可实现许多线程模式(POSIX 线程库如此之小是部分原因)。

最后一点:这有点超出了您的问题范围,但您也会了解真正需要生成多少线程。线程之间的上下文切换相对便宜,但成本绝对不为零。这意味着当产生更多线程时,会出现收益递减点。从操作系统的角度考虑一下:除了实际进行切换之外,算法还必须花费周期来决定何时进行上下文切换。这个成本并不是零。因此,当您进行更多线程编程时,您会发现另一种类型的优化是,何时在线程中执行尽可能多的工作,而不等待另一个线程完成工作。当然,您必须在设计的简洁性和速度优化之间取得平衡。这只是您设计应用程序时需要考虑的事情。

If you are simply testing for a simple change in state (when to exit), a condition variable is sufficient. Just make sure you find a good WinAPI example to follow: you almost certainly need test the state multiple times (unlike what your intuition may tell you).

If you intend to share tasks/events between threads, a good pattern is to use a producer-consumer pattern, based on a mutexed queue and a condition variable. A typical example is, you have one producer thread that produces jobs which are pushed onto the queue (eg write data to a different file per task). Then, you can have multiple consumer threads which will remove the task from the queue and act on them. To communicate between the threads, you can have a condition variable which will signal to the consumer threads that the mutexed queue may be empty. (Read up on condition variables to understand why I say "may" here).

As you do more and more thread programming, you will look for opportunities where mutexes are unnecessary. For example, if I have a ton of read-only data on disk and I want your threads to calculate on this data, you can read the data before spawning your threads. All your threads will then have access to this data without having to use locks, as long as they behave and do not write to the data. You will find that you implement many thread patterns with just mutexes and condition variables (part of the reason while the POSIX thread library is so small).

One last note: it's a bit out of the scope of your question, but you will also get a feel of how many threads you really need to spawn. Context-switches between threads are relatively cheap, but the costs is definitely non-zero. That means there is a point of diminishing returns when spawning more threads. Just think about it in terms of the OS: the algorithm must spend cycles to decide when to context switch in addition to actually do the switch. This cost is not zero. So another type of optimization you will find as you do more thread-programming is, when to do as much work as you can in the thread without waiting for another thread to do the work. Of course, you must strike a balance between cleanliness of your design and optimizing for speed. It's just something to think about as you design your application.

二智少女猫性小仙女2024-12-17 22:22:00
  1. boost::condition_variable 预期 C++11 的 std::condition_variable。截至今天(2011),已在 POSIX 接口系统(如 UNIX / LINUX)上完全实现,但仅在 Windows 上进行模仿(部分支持)
  2. Windows CONDITION_VARAIBLE 是实现 std::condition_varable 所需的“硬件” code> 在 Windows 中得到完全支持。但仅从 win6(Vista 和 2008)开始存在。世界上仍然有很多 XP(这就是为什么 mingw -pthread 在 Windows 中不受支持)。
  3. Winapi evvent 对象(请参阅 CreateEvent)可以模仿 posix 条件变量,但并不完全相同(在 POSIX 中,条件变量可用于根据具体情况弱化一个或全部。在 Windows 中,事件被创建为自动(如果有信号唤醒一个线程并自动重置)或手动(如果有信号弱,则一切都会等待它,直到它保持有信号状态。重置必须是手动的)并且不能根据情况改变行为:
  4. 忘记了信号和插槽。目的不是“当发生某些事情时弱化等待线程”。它们只是一个完全不同(不相关)的概念,
  5. 它是更通用的互斥体的“单进程”版本(对于 Windows 和 POSIX 来说是相同的)。区别在于 Windows 不区分递归和非递归:所有都是递归的)

也就是说,在事件(和条件变量)和互斥体(和关键部分)后面有不同的工作范围:

互斥体。 -本质上-保护不能同时运行的代码。它们本质上意味着“如果这段代码已经在执行,请等待另一段代码完成它”。

事件本质上是保护对尚未生成的资源的访问。它本质上意味着“在这里等待,直到有人承认可以过去”。

不同之处在于,互斥体是由发出信号的人发出信号的,而事件是由发出信号的人唤醒的人发出信号的。
请注意,这里的术语“信号”与“增强信号”中的信号概念无关,它与“委托链”的概念更相关。但这完全是另一个故事了。

  1. boost::condition_variable anticipate std::condition_variable of C++11. As of today (2011) is implemented fully on POSIX interfaced systems (like UNIX / LINUX) but only mimicked on windows (with partial support)
  2. windows CONDITION_VARAIBLE is the "hardware" that is needded to implement std::condition_varable in windows with full support. But exists only from win6 (Vista and 2008). The world is still poulated by a lot of XP (that's why mingw -pthread is not supported in windows).
  3. Winapi evvent objects (see CreateEvent) can mimic a posix condition variable but are not exactly the same (in POSIX a condition variable can be used to weak up just one or all, case by case. in Windows, an Event is created to be automatic (and if signaled wake-up one thread and autoresets) or manual (and if signaled weak up everything waits for it until it will remain signaled. Reset must be manual) and cannot change behavior case by case.
  4. Forgot signal & slots: their purpose is not "weak up a waiting thread when something happens". They are just a completely different (an unrelated) concept.
  5. CriticalSection is the "single process" version for the more general Mutex (that is the same for windows and POSIX, with the difference that Windows does not distinguish between recursive and non-recursive: all are recursive).

That said, behind events (and condition variable) and mutex (and critical sections) there is a different scope of work:

Mutexes -essentially- protect code that must not be run concurrently. They essentially means "if this piece of code is already in execution wait until the other will complete it".

Events -essentially- protect the access to resource not yet been produced. It essentially means "wait here until someone can grant that it is possible to go over".

The difference is that mutexes are signaled by the same who has unsignaled them, while events are unsignaled by the one that had been waked-up from who signaled them.
Note the the term "signal", here, has noting to do with the notion of signal in "boost signal", that is much more related to the concept of "delegate chain". But it is all another story.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文