如何在使用pthread库时,在C/C++中实现类似于Java中的wait和notify用于两个或多个线程之间的共享内存?
如何在使用pthread库时,在C/C++中实现类似于Java中的wait和notify用于两个或多个线程之间的共享内存?
与使用Java对象进行等待/通知不同,您需要两个对象:互斥锁和条件变量。它们使用pthread_mutex_init
和pthread_cond_init
进行初始化。
在Java对象上同步的地方,使用pthread_mutex_lock
和pthread_mutex_unlock
(请注意,在C中,您必须手动配对这些)。如果您不需要等待/通知,仅需锁定/解锁,则只需要互斥锁,而不需要条件变量。请记住,互斥锁不一定是“可递归”的。这意味着,如果您已经拥有锁,则无法再次获取锁,除非设置初始标志以指定您想要该行为。
在调用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一样,当您等待时,互斥锁将被释放。
与Java不同,在Java中,除非您持有监视器,否则无法调用notify
,但实际上,您确实可以在不持有互斥锁的情况下调用pthread_cond_signal
。通常不会获得任何好处,而且通常是一个非常糟糕的想法(因为通常您想要锁定-设置条件-信号-解锁)。因此,最好将其忽略并将其视为Java。
实际上没有太多需要注意的事项,基本模式与Java相同,并非巧合。但请阅读所有这些函数的文档,因为有各种标志和有趣的行为,您需要了解和/或避免。
在C++中,你可以比仅使用pthread API更好地应用RAII于互斥锁的加锁/解锁操作。但是,取决于你能够使用哪些C++库,你可能最好使用更符合C++风格的pthread函数的包装器。在您的标题中,您将C和C++混合在一起,随意使用“C/C++”。我希望您不是编写了一个混合两者的程序。
如果您使用的是C++11,则会发现可移植的pthread替代方案(在POSIX系统上,它通常在幕后使用pthread)。
您可以使用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();
}
pthread_cond_wait和pthread_cond_signal可以基于某个条件进行同步。
使用条件变量是一种方法:在Linux下使用pthread
库时可以使用它们(请参见链接)。
条件变量是类型为pthread_cond_t的变量,与适当的等待函数和稍后的进程继续使用。
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));
。