C++ 在什么情况下,在C++;?

C++ 在什么情况下,在C++;?,c++,multithreading,semaphore,C++,Multithreading,Semaphore,在我读过的有关多线程的所有参考资料中,与信号量相比,互斥体的使用和讨论更为频繁。我的问题是什么时候在互斥上使用信号量?我在Boost线程中没有看到信号量。这是否意味着现在信号量不再使用了 据我所知,信号量允许多个线程共享一个资源。只有当这些线程只读取资源而不写入时,这才是可能的。这是否正确?控制对多个线程(进程间或进程内)共享的有限数量资源的访问 在我们的应用程序中,我们有一个非常繁重的资源,我们不想为每个M个工作线程分配一个资源。因为工作线程只需要工作的一小部分资源,所以我们很少同时使用超过两

在我读过的有关多线程的所有参考资料中,与信号量相比,互斥体的使用和讨论更为频繁。我的问题是什么时候在互斥上使用信号量?我在Boost线程中没有看到信号量。这是否意味着现在信号量不再使用了


据我所知,信号量允许多个线程共享一个资源。只有当这些线程只读取资源而不写入时,这才是可能的。这是否正确?

控制对多个线程(进程间或进程内)共享的有限数量资源的访问

在我们的应用程序中,我们有一个非常繁重的资源,我们不想为每个M个工作线程分配一个资源。因为工作线程只需要工作的一小部分资源,所以我们很少同时使用超过两个资源


因此,我们分配了N个资源,并将它们放在初始化为N的信号量后面。当超过N个线程试图使用该资源时,它们会一直阻塞,直到有一个可用。

互斥锁的典型用例(在任何时候只允许一个线程访问一个资源)比信号量的典型用法要常见得多。但信号量实际上是更一般的概念:互斥体(几乎)是信号量的特例

典型的应用程序是:您不希望创建超过(例如)5个数据库连接。无论有多少工作线程,它们都必须共享这5个连接。或者,如果在N核机器上运行,可能需要确保某些CPU/内存密集型任务不会同时在超过N个线程中运行(因为这只会由于上下文切换和缓存抖动效应而降低吞吐量)。您甚至可能希望将并行CPU/内存密集型任务的数量限制为N-1,这样系统的其余部分就不会饿死。或者设想某个任务需要大量内存,因此同时运行该任务的N个以上实例将导致分页。您可以在这里使用一个信号量,以确保此特定任务在同一时间运行的实例不超过N个

编辑/PS:从你的问题“只有当那些线程只读取资源而不写入时,这才可能。这是正确的吗?”和你的评论,在我看来,似乎你认为资源是一个变量或流,可以读取或写入,一次只能由一个线程写入。不要。在这种情况下,这是一种误导


想想像“水”这样的资源。你可以用水洗碗。我可以同时用水洗碗。我们不需要任何形式的同步,因为我们都有足够的水。我们不一定用同样的水。(你不能“读”或“写”水。)但水的总量是有限的。因此,不可能有任何数量的派对同时洗碗。这种同步是通过信号量完成的。通常不使用水,而是使用其他有限的资源,如内存、磁盘空间、IO吞吐量或CPU内核。

据我所知,信号量是当今与IPC密切相关的术语。这仍然意味着许多进程可以修改受保护的变量,但在进程之间,此功能受操作系统支持

通常,我们不需要一个变量,一个简单的互斥体就可以满足我们的所有需求。如果我们仍然需要一个变量,我们可能会自己编写——“变量+互斥”以获得更多的控制


Resume:我们在多线程中不使用信号量,因为通常使用互斥来简化和控制,我们为IPC使用信号量,因为它支持操作系统,是进程同步机制的正式名称。

我觉得没有简单的方法可以回答你的问题而不忽略信号量的一些重要信息。人们已经写过了,所以任何一两段的答案都是有害的。一本流行的书是。。。对于那些不喜欢大书的人:)

下面是一个不错的例子,它详细介绍了信号量的使用方法以及它们的用途

更新:
丹指出了我的例子中的一些错误,我将留下比我更好的解释的参考文献:)

下面是一些参考资料,说明了使用信号量的正确方法:



摘自:

互斥允许进程间同步。如果使用名称实例化互斥体(如上面的代码所示),互斥体将变为系统范围。如果您在许多不同的应用程序之间共享同一个库,并且需要阻止对访问无法共享资源的关键代码部分的访问,那么这将非常有用

最后是信号量类。假设您有一个真正的CPU密集型方法,并且还利用了控制访问所需的资源(使用互斥体:)。您还确定,最多五次对该方法的调用是您的计算机在不使其无响应的情况下所能处理的全部。这里最好的解决方案是使用Semaphore类,它允许您限制一定数量的线程对资源的访问


从我在大学里对信号量和互斥量的了解来看,信号量更多的是理论对象,而互斥量是信号量的一种实现。考虑到这一点,信号量更加灵活

互斥锁高度依赖于实现。它们已针对二进制锁定目的进行了优化。互斥的正常用例是二进制信号量


通常,在尝试编写无bug的多线程代码时,简单性会有所帮助。互斥锁的使用越来越多,因为它们的简单性有助于避免因使用信号量而产生的复杂死锁情况。

Boost.Thread有互斥锁和条件变量。纯粹就
struct sem {
    mutex m;
    condvar cv;
    unsigned int count;
};

sem_init(s, value)
    mutex_init(s.m);
    condvar_init(s.cv);
    count = value;

sem_wait(s)
    mutex_lock(s.m);
    while (s.count <= 0) {
        condvar_wait(s.cv, s.m);
    }
    --s.count;
    mutex_unlock(s.m);

sem_post(s)
    mutex_lock(s.m);
    ++s.count;
    condvar_broadcast(s.cv)
    mutex_unlock(s.m);