34

How to wait and notify like in Java In C/C++ for shared memory between two or more thread?I use pthread library.

4

6 回答 6

38

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

在 Java 对象上同步的地方,使用pthread_mutex_lockand pthread_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 中一样,等待函数可能会产生虚假唤醒,因此您需要在调用信号之前设置一些条件,并在调用等待之后检查,并且您需要pthread_cond_wait循环调用。与在 Java 中一样,互斥锁在您等待时被释放。

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

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

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

于 2010-01-18T15:28:33.903 回答
7

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

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

您可以使用std::condition_variable+std::mutex等待/通知。这个例子展示了如何:

#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 的其他一些优势:

  1. 此代码不包含单个原始指针(这是危险的
  2. lambda 表达式
  3. 其他各种句法 swagg
于 2013-12-06T11:47:45.177 回答
6

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

于 2010-01-18T11:17:30.240 回答
4

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

条件变量是 pthread_cond_t 类型的变量,与适当的函数一起用于等待和稍后的进程继续。

于 2010-01-18T11:14:40.560 回答
2

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

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

于 2013-06-19T16:30:14.740 回答
1

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

于 2010-01-18T11:15:22.477 回答