在 C/C++ 共享内存中等待和通知

Posted

技术标签:

【中文标题】在 C/C++ 共享内存中等待和通知【英文标题】:wait and notify in C/C++ shared memory 【发布时间】:2011-01-06 07:55:14 【问题描述】:

如何在 C/C++ 中的 Java 中等待和通知两个或多个线程之间的共享内存?我使用 pthread 库。

【问题讨论】:

【参考方案1】:

如果可用,您可以使用 POSIX 信号量。 pthread 库具有互斥锁,它也可能对您有用。

【讨论】:

【参考方案2】:

在您的标题中,您将 C 和 C++ 如此随意地混合为“C/C++”。我希望,您编写的程序不是两者的混合体。

如果您使用的是 C++11,您会发现一个可移植的(因为 C++,所以)比 pthreads 更安全/更易于使用的替代方案(在 POSIX 系统上,它通常在后台使用 pthreads)。

您可以使用std::condition_variable + std::mutex 等待/通知。 This example 显示如何:

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex m;
std::condition_variable cv;
std::string data;
bool mainReady = false;
bool workerReader = false;

void worker_thread()

    // Wait until main() sends data
    
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, []return mainReady;);
    

    std::cout << "Worker thread is processing data: " << data << std::endl;
    data += " after processing";

    // Send data back to main()
    
        std::lock_guard<std::mutex> lk(m);
        workerReady = true;
        std::cout << "Worker thread signals data processing completed\n";
    
    cv.notify_one();


int main()

    std::thread worker(worker_thread);

    data = "Example data";
    // send data to the worker thread
    
        std::lock_guard<std::mutex> lk(m);
        mainReady = true;
        std::cout << "main() signals data ready for processing\n";
    
    cv.notify_one();

    // wait for the worker
    
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, []return workerReady;);
    
    std::cout << "Back in main(), data = " << data << '\n';


    // wait until worker dies finishes execution
    worker.join();

这段代码还强调了 C++ 相对于 C 的其他一些优势:

    此代码不包含单个原始指针 (which are treacherous) lambda expressions 其他各种syntactic swagg。

【讨论】:

“我希望,你写的程序不是两者的混合体”混合它们有什么问题? @mFeinstein 在实践中,您经常混合使用它们。但是,当有疑问时,在思考“哦……我应该使用原始指针还是智能指针?”时,您已经在使用 C++(因为 C 没有智能指针),所以您肯定想使用智能指针,除非有一些 API 或其他限制禁止使用它们,或者它们显然是不必要的等等......可以花在解决更难的问题上。【参考方案3】:

您需要两个对象,而不是用于等待/通知的 Java 对象:互斥体和条件变量。这些用pthread_mutex_initpthread_cond_init 初始化。

如果您需要在 Java 对象上进行同步,请使用 pthread_mutex_lockpthread_mutex_unlock(请注意,在 C 中您必须自己手动配对)。如果您不需要等待/通知,只需锁定/解锁,那么您不需要条件变量,只需互斥锁。请记住,互斥锁不一定是“递归的”,这意味着如果您已经持有锁,则除非您设置 init 标志以表示您想要该行为,否则您将无法再次使用它。

如果您想拨打java.lang.Object.wait,请拨打pthread_cond_waitpthread_cond_timedwait

如果您想拨打java.lang.Object.notify,请拨打pthread_cond_signal

如果您想拨打java.lang.Object.notifyAll,请拨打pthread_cond_broadcast

在 Java 中,等待函数可能会产生虚假唤醒,因此您需要在调用 signal 之前设置一些条件,并在调用 wait 之后检查,并且您需要在循环中调用 pthread_cond_wait。与在 Java 中一样,互斥锁会在您等待时释放。

与 Java 不同,在 Java 中,除非您持有监视器,否则您不能调用 notify,您可以实际上在不持有互斥锁的情况下调用 pthread_cond_signal。但是,它通常不会为您带来任何好处,而且通常是一个非常糟糕的主意(因为通常您想要锁定 - 设置条件 - 信号 - 解锁)。所以最好只是忽略它,像 Java 一样对待它。

实际上并没有更多内容,基本模式与 Java 相同,并非巧合。不过,请务必阅读所有这些功能的文档,因为您想了解和/或避免各种标志和有趣的行为。

在 C++ 中,您可以比仅使用 pthreads API 做得更好。您至少应该将 RAII 应用于互斥锁/解锁,但根据您可以使用的 C++ 库,您最好为 pthreads 函数使用更 C++ 的包装器。

【讨论】:

【参考方案4】:

如果您不关心可移植性,Linux 提供了 eventfd,它可以为您提供所需的一切。每个 eventfd 都有一个内部计数器。在默认模式下,如果计数器为零,则从 eventfd 读取阻塞,否则立即返回。写入它会增加内部计数器。

因此,等待调用将只是一个uint64_t buf_a; read(event_fd, &amp;buf_a, sizeof(buf_a));,其中 buf 必须是一个 8 字节的缓冲区。要通知等待的线程,您可以使用uint64_t buf_b = 1; write(event_fd, &amp;buf_b, sizeof(buf_b));

【讨论】:

【参考方案5】:

pthread_cond_wait 和 pthread_cond_signal 可用于根据条件进行同步

【讨论】:

【参考方案6】:

使用 Condition Variables 是一种方法:在 Linux 下使用 pthread 库时可以使用这些方法(参见链接)。

条件变量是 键入 pthread_cond_t 并与 等待的适当功能 之后,流程继续。

【讨论】:

以上是关于在 C/C++ 共享内存中等待和通知的主要内容,如果未能解决你的问题,请参考以下文章

如何在python和C / C ++中使用共享内存

是否可以在 Windows 中的 PHP 和 C 之间共享内存?

在不同步的情况下读写 SysV 共享内存(使用信号量、C/C++、Linux)

C/C++使用Windows的API实现共享内存以及同步

使用 Boost.Interprocess 使进程等待直到资源加载到共享内存中

共享内存实现上的 C++ 内存池:这种分配和释放方法是不是正确?