我想在Rust中构建一个单生产者多消费者示例,其中生产者注定有不超过10个未完成的项目。我在C中使用互斥量和两个condvars为解决方案建模。一种condvar是在没有消耗的东西时等待消费者,而另一种condvar是在未消费的物品数大于10时等待生产者。C代码如下。
据我从Rust文档了解到的,std::sync::Mutex
和std::sync::Condvar
之间必须存在1-1连接,因此我无法对C解决方案进行准确的翻译。
是否有其他方法可以使用std::sync::Mutex
和std::sync::Condvar
在Rust中达到相同的目的(我看不到)。
#define _GNU_SOURCE
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
//
// This is a simple example of using a mutex and 2 condition variables to
// sync a single writer and multiple readers interacting with a bounded (fixed max size) queue
//
// in this toy example a queue is simulated by an int counter n_resource
//
int n_resource;
pthread_cond_t rdr_cvar;
pthread_cond_t wrtr_cvar;
pthread_mutex_t mutex;
void reader(void* data)
{
long id = (long)data;
for(;;) {
pthread_mutex_lock(&mutex);
while (n_resource <= 0) {
pthread_cond_wait(&rdr_cvar, &mutex);
}
printf("Reader %ld n_resource = %d\n", id, n_resource);
--n_resource;
// if there are still things to read - singla one reader
if(n_resource > 0) {
pthread_cond_signal(&rdr_cvar);
}
// if there is space for the writer to add another signal the writer
if(n_resource < 10) {
pthread_cond_signal(&wrtr_cvar);
}
pthread_mutex_unlock(&mutex);
}
}
void writer(void* data)
{
for(;;) {
pthread_mutex_lock(&mutex);
printf("Writer before while n_resource %d \n", n_resource);
while (n_resource > 10) {
pthread_cond_wait(&wrtr_cvar, &mutex);
}
printf("Writer after while n_resource %d \n", n_resource);
++n_resource;
// if there is something for a reader to read signal one of the readers.
if(n_resource > 0) {
pthread_cond_signal(&rdr_cvar);
}
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t rdr_thread_1;
pthread_t rdr_thread_2;
pthread_t wrtr_thread;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&rdr_cvar, NULL);
pthread_cond_init(&wrtr_cvar, NULL);
pthread_create(&rdr_thread_1, NULL, &reader, (void*)1L);
pthread_create(&rdr_thread_2, NULL, &reader, (void*)2L);
pthread_create(&wrtr_thread, NULL, &writer, NULL);
pthread_join(wrtr_thread, NULL);
pthread_join(rdr_thread_1, NULL);
pthread_join(rdr_thread_2, NULL);
}
最佳答案
尽管CondVar
仅需要与一个Mutex
相关联,但Mutex
不必仅与一个CondVar
相关联。
例如,以下代码似乎可以正常工作-您可以在playground上运行它。
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
struct Q {
rdr_cvar: Condvar,
wrtr_cvar: Condvar,
mutex: Mutex<i32>,
}
impl Q {
pub fn new() -> Q {
Q {
rdr_cvar: Condvar::new(),
wrtr_cvar: Condvar::new(),
mutex: Mutex::new(0),
}
}
}
fn writer(id: i32, qq: Arc<Q>) {
let q = &*qq;
for i in 0..10 {
let guard = q.mutex.lock().unwrap();
let mut guard = q.wrtr_cvar.wait_while(guard, |n| *n > 3).unwrap();
println!("{}: Writer {} n_resource = {}\n", i, id, *guard);
*guard += 1;
if *guard > 0 {
q.rdr_cvar.notify_one();
}
if *guard < 10 {
q.wrtr_cvar.notify_one();
}
}
}
fn reader(id: i32, qq: Arc<Q>) {
let q = &*qq;
for i in 0..10 {
let guard = q.mutex.lock().unwrap();
let mut guard = q.rdr_cvar.wait_while(guard, |n| *n <= 0).unwrap();
println!("{} Reader {} n_resource = {}\n", i, id, *guard);
*guard -= 1;
if *guard > 0 {
q.rdr_cvar.notify_one();
}
if *guard < 10 {
q.wrtr_cvar.notify_one();
}
}
}
fn main() {
let data = Arc::new(Q::new());
let data2 = data.clone();
let t1 = thread::spawn(move || writer(0, data2));
let t2 = thread::spawn(move || reader(1, data));
t1.join().unwrap();
t2.join().unwrap();
}
关于rust - 如何创建具有两个condvar的互斥锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64127981/