How to wait and notify like in Java In C/C++ for shared memory between two or more thread?I use pthread library.
6 回答
您需要两个对象,而不是用于等待/通知的 Java 对象:互斥体和条件变量。这些用pthread_mutex_init
和初始化pthread_cond_init
。
在 Java 对象上同步的地方,使用pthread_mutex_lock
and pthread_mutex_unlock
(请注意,在 C 语言中,您必须自己手动配对)。如果您不需要等待/通知,只需锁定/解锁,那么您不需要条件变量,只需互斥锁。请记住,互斥锁不一定是“递归的”,这意味着如果您已经持有锁,则除非您设置 init 标志以表示您想要该行为,否则您将无法再次使用它。
你会打电话的地方java.lang.Object.wait
,打电话pthread_cond_wait
或pthread_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++ 的包装器。
在您的标题中,您将 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 的其他一些优势:
- 此代码不包含单个原始指针(这是危险的)
- lambda 表达式
- 其他各种句法 swagg。
pthread_cond_wait 和 pthread_cond_signal 可用于根据条件进行同步
使用条件变量是一种方法:pthread
在 Linux 下使用库时可以使用这些方法(参见链接)。
条件变量是 pthread_cond_t 类型的变量,与适当的函数一起用于等待和稍后的进程继续。
如果您不关心可移植性,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));
。
如果可用,您可以使用 POSIX 信号量。pthread 库具有互斥锁,它也可能对您有用。