Rust 中的缓冲区与 Mutex 和 Condvar

2023-12-02

我正在尝试用单个消费者和单个生产者实现一个缓冲区。我只使用了 POSIX 信号量,但是它们在 Rust 中不可用,我正在尝试使用 Rust 同步原语实现一个简单的信号量问题(Mutex, Condvar, Barrier,...)但我不想使用频道。

我的代码行为太不规则,某些情况下进展顺利,有时它只是停在某个数字上,而在其他情况下它只是不开始计数。

如果我在主线程中等待 1 秒直到发送Condvar通知,但不保证不会陷入僵局。

如何修复这个程序?我理解吗Condvars wrong?

use std::thread;
use std::sync::{Arc, Condvar, Mutex};

struct Buffer {
    is_data: Mutex<bool>,
    is_data_cv: Condvar,
    is_space: Mutex<bool>,
    is_space_cv: Condvar,
    buffer: Mutex<i32>,
}

fn producer(buffer: Arc<Buffer>) {
    for i in 0..50 {
        loop {
            let mut is_space = buffer
                .is_space_cv
                .wait(buffer.is_space.lock().unwrap())
                .unwrap();
            if *is_space {
                {
                    let mut hueco = buffer.buffer.lock().unwrap();
                    *hueco = i;
                }

                *is_space = false;
                {
                    let mut is_data = buffer.is_data.lock().unwrap();
                    *is_data = true;
                }
                buffer.is_data_cv.notify_one();
                break;
            }
        }
    }
}

fn consumer(buffer: Arc<Buffer>) {
    for i in 0..50 {
        loop {
            let mut is_data = buffer
                .is_data_cv
                .wait(buffer.is_data.lock().unwrap())
                .unwrap();
            if *is_data {
                {
                    let hueco = buffer.buffer.lock().unwrap();
                    println!("{}", *hueco);
                }
                *is_data = false;
                {
                    let mut is_space = buffer.is_space.lock().unwrap();
                    *is_space = true;
                }
                buffer.is_space_cv.notify_one();
                break;
            }
        }
    }
}

fn main() {
    let buffer = Arc::new(Buffer {
        is_data: Mutex::new(false),
        is_data_cv: Condvar::new(),
        is_space: Mutex::new(true),
        is_space_cv: Condvar::new(),
        buffer: Mutex::new(0),
    });
    let b = buffer.clone();
    let p = thread::spawn(move || {
        producer(b);
    });
    let b = buffer.clone();
    let c = thread::spawn(move || {
        consumer(b);
    });

    //thread::sleep_ms(1000);

    buffer.is_space_cv.notify_one();
    c.join();
}

我鼓励您创建更小的方法并重用现有的 Rust 类型,例如Option。这将使您可以大大简化代码——只有一个Mutex和一个Condvar:

use std::thread;
use std::sync::{Arc, Condvar, Mutex};

#[derive(Debug, Default)]
struct Buffer {
    data: Mutex<Option<i32>>,
    data_cv: Condvar,
}

impl Buffer {
    fn insert(&self, val: i32) {
        let mut lock = self.data.lock().expect("Can't lock");
        while lock.is_some() {
            lock = self.data_cv.wait(lock).expect("Can't wait");
        }
        *lock = Some(val);
        self.data_cv.notify_one();
    }

    fn remove(&self) -> i32 {
        let mut lock = self.data.lock().expect("Can't lock");
        while lock.is_none() {
            lock = self.data_cv.wait(lock).expect("Can't wait");
        }
        let val = lock.take().unwrap();
        self.data_cv.notify_one();
        val
    }
}

fn producer(buffer: &Buffer) {
    for i in 0..50 {
        println!("p: {}", i);
        buffer.insert(i);
    }
}

fn consumer(buffer: &Buffer) {
    for _ in 0..50 {
        let val = buffer.remove();
        println!("c: {}", val);
    }
}

fn main() {
    let buffer = Arc::new(Buffer::default());

    let b = buffer.clone();
    let p = thread::spawn(move || {
        producer(&b);
    });

    let b = buffer.clone();
    let c = thread::spawn(move || {
        consumer(&b);
    });

    c.join().expect("Consumer had an error");
    p.join().expect("Producer had an error");
}

如果你想有更多的性能(基准测试看看是否值得),你可以Condvars 分别表示“空”和“满”条件:

#[derive(Debug, Default)]
struct Buffer {
    data: Mutex<Option<i32>>,
    is_empty: Condvar,
    is_full: Condvar,
}

impl Buffer {
    fn insert(&self, val: i32) {
        let mut lock = self.data.lock().expect("Can't lock");
        while lock.is_some() {
            lock = self.is_empty.wait(lock).expect("Can't wait");
        }
        *lock = Some(val);
        self.is_full.notify_one();
    }

    fn remove(&self) -> i32 {
        let mut lock = self.data.lock().expect("Can't lock");
        while lock.is_none() {
            lock = self.is_full.wait(lock).expect("Can't wait");
        }
        let val = lock.take().unwrap();
        self.is_empty.notify_one();
        val
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Rust 中的缓冲区与 Mutex 和 Condvar 的相关文章

随机推荐

  • PyCharm 中的子包和相对导入

    我正在使用Python 2 python version Python 2 7 13 Continuum Analytics Inc 我有以下项目结构 foo bar1 init py mod1 py bar2 init py mod2 p
  • 内联函数有一个非内联副本

    在阿格纳 雾的优化C 手册他有一节 内联函数有一个非内联副本 他在其中写道 函数内联的复杂之处在于可能从另一个模块调用相同的函数 编译器必须制作内联函数的非内联副本 以便该函数也可能从另一个模块调用 如果没有其他模块调用该函数 则该非内联副
  • 如何从 JSON 流中删除特殊字符,以便我可以使用 gson API 将 JSON 对象转换为 JAVA 对象?

    我正在尝试使用 Google gson API 将 JSON 对象序列化为 java 对象 我需要从此流中删除特殊字符以进行序列化 我该如何实现这一目标 这是我从请求中获取的 JSON 对象 color 北极白 imageUrl http
  • 将选定的列从 CSV 文件导入到 SQL Server 表

    我正在尝试将数据从 CSV 文件导入到 SQL Server 2008 表 数据上传正在工作 但我只想导入选定的列 而不是全部 并将它们添加到具有相同编号的新表中 使用向导 但它没有发生 向导正在选择所有列 那么是否可以使用向导仅导入选定的
  • R 中匹配整个字符串

    考虑以下字符串 string I have 1 file and 11 folders 我想更换图案 1用这个词one 但我不想修改 11 结果应该是 string I have one file and 11 folders 我努力了 s
  • 在 C/C++ 中创建 10 位数据类型 [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 可以创建10位数据类型吗 我可以用uint16 t uint32 t等等 但是如果我想使用怎么办uint10 t or uint12 t 这可能吗 您不能拥有大小不是字节倍数的类
  • Chrome console.log(elementID) 在控制台中输出元素

  • 如何从 Outlook 联系人中获取列中列出的姓名的电子邮件地址?

    我是 VBA 新手 我需要帮助做一些事情 如下图所示 我有一个名字列表 我想要做的是根据 A 列中的姓名从 Outlook 联系人列表中检索他们的电子邮件地址 电子邮件地址分散在不同的联系人文件夹中 并将其粘贴到 B 列中 或者 是否可以从
  • 如何编写一个方法来计算 ruby​​ 中字符串中最常见的子字符串?

    我的这个程序带有阶级 DNA 该程序计算字符串中最常见的 k 聚体 因此 它正在寻找长度为 k 的字符串中最常见的子字符串 一个示例是使用 AACCAATCCG 字符串创建 dna1 对象 count k mer 方法将查找长度为 k 的子
  • Spring - JPA - 读取工作但坚持给我没有可用的事务EntityManager。为什么?

    我正在使用 spring 和 JPA 构建一个应用程序 我的读取功能正在工作 但是当我尝试保存任何对象时 出现异常没有可用的事务性 EntityManager 这是我的 web xml 文件
  • 如何列出连接交换机的端口和 Mac 地址 (Cisco) C#

    大家好我想问一下如何使用C 列出连接到交换机的设备的端口和mac地址 我找到了适用于戴尔交换机的代码 我需要它用于思科交换机 using SnmpSharpNet using System using System Collections
  • Android 中的 log4j 支持

    我正在尝试将现有的 SDK 硬塞到 Android 设备上 并且所述 SDK 的依赖项之一是 Apache log4j 我能够将我的测试程序加载到 android 模拟器上 但是当调用 log4j 对象 PropertySetter 时 程
  • 带有图像的 MVC3 ActionLink(但没有 MvcFutures)?

    我想知道是否有人知道是否可以使用任何 开箱即用 的 ASP NET MVC3 帮助程序来生成 链接按钮 我目前使用以下内容 a class button title My Action href Url Action img alt My
  • 在 Mono 上使用 X509Certificate2 - 使用公钥和私钥加载?

    现在 我尝试像这样实例化 X509Certificate2 cert new X509Certificate2 Resources cred Where Resources cred is a byte 代表一个 pfx file 这在 W
  • 无法通过 PDO 连接到 AWS RDS

    我在AWS中设置了一个MySQL RDS实例 实例化实例后 我尝试从 EC2 的命令行连接它 它工作没有问题 但是 当我尝试通过 PHP 代码进行连接时 出现错误 以下是我尝试测试连接性的示例代码
  • Safari 11 中的 SVG 动画错误

    如您所知 昨晚发布了新的 Safari Safari 11 最后一个版本在 SVG 动画上创建了一个错误 该错误在 safari 10 上工作正常 或者在 chrome 上仍然工作 我只是不知道如何解决这个问题 我尝试了一切 webkit
  • 使用 psexec 在远程计算机上运行 AutoIt

    我正在尝试在远程计算机上运行 AutoIt 脚本 psexec exe accepteula remotemachine u admin p password C Program Files AutoIt3 AutoIt3 exe C Us
  • 在 Prolog 中解决逻辑难题 [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 我正在阅读 立即学习 Prolog 其中我自己无法解决的练习之一如下 有一条街 有三 邻近的房屋都有一个 不同的颜色 它们有红色 蓝色 和绿色 不同的人 不同民族生活在不同的地方
  • 如何从Android应用程序访问标准输入?

    我正在使用磁条阅读器 它似乎输出到标准输入 当我将其插入 Android 设备 打开记事本应用程序并滑动时 它会自动将字符串粘贴到应用程序中 就像我键入了它一样 这就是为什么我认为它输出到标准 IO 我想以编程方式读取数据 如何访问 and
  • Rust 中的缓冲区与 Mutex 和 Condvar

    我正在尝试用单个消费者和单个生产者实现一个缓冲区 我只使用了 POSIX 信号量 但是它们在 Rust 中不可用 我正在尝试使用 Rust 同步原语实现一个简单的信号量问题 Mutex Condvar Barrier 但我不想使用频道 我的