0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何利用Mutex解决并发写文件乱序的问题?

jf_wN0SrCdH 来源:京东云开发者 2023-08-12 09:54 次阅读

在实际开发过程中,我们可能会遇到并发写文件的场景,如果处理不当很可能出现文件内容乱序问题。下面我们通过一个示例程序描述这一过程并给出解决该问题的方法。

use std::{
    fs::{self, File, OpenOptions},
    io::{Write},
    sync::Arc,
    time::{SystemTime, UNIX_EPOCH},
};
use tokio::JoinSet;


fn main() {
    println!("parallel write file!");
    let max_tasks = 200;
    let _ = fs::remove_file("/tmp/parallel");
    let file_ref = OpenOptions::new()
        .create(true)
        .write(true)
        .append(true)
        .open("/tmp/parallel")
        .unwrap();


    let mut set: JoinSet<()> = JoinSet::new();
    let rt = tokio::new().unwrap();
    rt.block_on(async {
        loop {
            while set.len() >= max_tasks {
                set.join_next().await;
            }
            未做写互斥函数
            let mut file_ref = OpenOptions::new()
                .create(true)
                .write(true)
                .append(true)
                .open("/tmp/parallel")
                .unwrap();
            set.spawn(async move { write_line(&mut file_ref) });
        }
    });
}


fn write_line(file: &mut File) {
    for i in 0..1000 {
        let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
        let mut content = now.as_secs().to_string();
        content.push_str("_");
        content.push_str(&i.to_string());


        file.write_all(content.as_bytes()).unwrap();
        file.write_all("
".as_bytes()).unwrap();
        file.write_all("
".as_bytes()).unwrap();
    }
}

代码不复杂,tokio 实现一个并发runtime,写文件函数是直接写时间戳,为了方便展示乱序所以写入两次换行。

输出的文本大概长这样:


1691287258_979










1691287258_7931691287258_301


1691287258_7431691287258_603


1691287258_8941691287258_47












1691287258_895
1691287258_553


1691287258_950
1691287258_980




1691287258_48
1691287258_302


1691287258_896
1691287258_744








1691287258_6041691287258_554

很明显,写入并未达到预期,间隔并不平均,函数内部的执行步骤是乱序的。

我们把上面的程序改造一下:


use std::{
    fs::{self, File, OpenOptions},
    io::Write,
    sync::Arc,
    time::{SystemTime, UNIX_EPOCH},
};
use tokio::Mutex;
use tokio::JoinSet;


fn main() {
    println!("parallel write file!");
    let max_tasks = 200;
    let _ = fs::remove_file("/tmp/parallel");
    let file_ref = OpenOptions::new()
        .create(true)
        .write(true)
        .append(true)
        .open("/tmp/parallel")
        .unwrap();


    let f = Arc::new(Mutex::new(file_ref));


    let mut set: JoinSet<()> = JoinSet::new();
    let rt = tokio::new().unwrap();
    rt.block_on(async {
        loop {
            while set.len() >= max_tasks {
                set.join_next().await;
            }


            let mut file = Arc::clone(&f);
            set.spawn(async move { write_line_mutex(&mut file).await });
        }
    });
}


async fn write_line_mutex(mutex_file: &Arc>) {
    for i in 0..1000 {
        let mut f = mutex_file.lock().await;
        let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
        let mut content = now.as_secs().to_string();
        content.push_str("_");
        content.push_str(&i.to_string());


        f.write_all(content.as_bytes()).unwrap();
        f.write_all("
".as_bytes()).unwrap();
        f.write_all("
".as_bytes()).unwrap();
    }
}

这次我们用到了tokio::Mutex,write_line_mutex函数在每次执行写任务以前先获取文件互斥锁。

看看这次的文件内容:


1691288040_374


1691288040_374


1691288040_374


1691288040_375


1691288040_374


1691288040_374


1691288040_374


1691288040_374


1691288040_374


1691288040_374


1691288040_374


1691288040_374


1691288040_374


1691288040_374


1691288040_375


1691288040_375


1691288040_374


1691288040_375


1691288040_375


1691288040_375


1691288040_375


1691288040_375


1691288040_375


1691288040_375


1691288040_375


1691288040_375


1691288040_375

写入的格式正确,保证每次函数写函数完整执行。

关于文件写互斥这点事儿,今儿就聊到这。






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Unix系统
    +关注

    关注

    0

    文章

    15

    浏览量

    9581
  • ARC
    ARC
    +关注

    关注

    0

    文章

    36

    浏览量

    16355
  • rust语言
    +关注

    关注

    0

    文章

    58

    浏览量

    2958

原文标题:文盘Rust -- Mutex解决并发写文件乱序问题

文章出处:【微信号:Rust语言中文社区,微信公众号:Rust语言中文社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    详解linux内核中的mutex同步机制

    在linux内核中,互斥量(mutex,即mutual exclusion)是一种保证串行化的睡眠锁机制。和spinlock的语义类似,都是允许一个执行线索进入临界区,不同的是当无法获得锁的时候
    的头像 发表于 05-13 08:56 6318次阅读
    详解linux内核中的<b class='flag-5'>mutex</b>同步机制

    Linux内核同步机制mutex详解

    在linux内核中,互斥量mutex是一种保证CPU串行运行的睡眠锁机制。和spinlock类似,都是同一个时刻只有一个线程进入临界资源,不同的是,当无法获取锁的时候,spinlock原地自旋,而mutex则是选择挂起当前线程,进入阻塞状态。所以,
    发表于 06-26 16:05 541次阅读

    Raw-os mutex

    1mutex 支持FIFO 和PRIO 的任务阻塞策略,如果是FIFO 的话阻塞队列的顺序是按照先来后到的次序去排列阻塞任务,PRIO 策略的话是按照优先级的排序。具体的设置可以直接设置这个结构体中
    发表于 02-27 14:03

    关于mutex

    mutex的出现是为了解决优先级反转的问题,由于优先级反转对实时性影响太大,所以mutex 的稳定性直接影响了实时性。纵观目前多种实时操作系统mutex 的设计原理是多多少少有一点问题的,raw
    发表于 02-27 14:34

    Linux Shell多进程并发以及并发数控制

    &这三个命令就会被同时送往linux后台执行,在这个程度上,认为这三个命令并发执行了。1.2. linux文件描述符文件描述符(缩写fd)在形式上是一个非负整数。实际上,它是一个索引值,指向
    发表于 08-28 15:53

    「正点原子Linux连载」第四十七章Linux并发与竞争

    。47.1 并发与竞争1、并发与竞争简介并发就是多个“用户”同时访问同一个共享资源,比如你们公司有一台打印机,你们公司的所有人都可以使用。现在小李和小王要同时使用这一台打印机,都要打印一份文件
    发表于 03-19 15:03

    Linux中常见并发访问的保护机制设计原理浅析

    进入临界区。对于有些情况,我们是可以区分读写操作的。因此,我们希望对于读操作的进程可以并发进行。对于操作只限于一个进程进入临界区。而这种同步机制就是读写锁。读写锁一般具有以下几种性质。同一时间有且仅有
    发表于 09-24 10:24

    labview写入access数据库乱序问题

    用database insert 插入数据,移位寄存器当作顺序编号,发现不管循环框频率设多少,到编号713这里必定会跳到737,然后中间这段会在1035后出现,其他地方也有类似的乱序,多次写入乱序
    发表于 08-09 10:23

    并发性程序并发工作效率低吗

    第一、并发性程序并发工作效率低在裸机软件时,不可避免的在主程序中会有一个超级大的 while(1) 循环,这里面几乎包含整个项目的所有业务逻辑。因为每个业务逻辑里面都会有 delay 这...
    发表于 08-20 08:26

    STM32G473是如何利用DMA接收并发送数据的

    STM32G473是如何利用DMA接收并发送数据的?其实现方法是什么?
    发表于 12-08 07:18

    互斥量Mutex相关资料推荐

    这里目录标题概述API二级目录三级目录概述APItx_mutex_createtx_mutex_deletetx_mutex_gettx_mutex_put二级目录三级目录
    发表于 02-22 07:40

    适用于IPTV大并发应用的文件格式

    分析交互式网络电视(IPTV)大并发应用的特性,提出一种适用于IPTV大并发应用的服务器内部文件格式cl4文件格式。该文件格式采用了符合IP
    发表于 04-15 10:02 17次下载

    Linux多线程同步互斥量Mutex详解

    pthread_mutex_destroy(pthread_mutex_t *mutex);头文件:返回值: 成功则返回0, 出错则返回错误编号.说明: 如果使用默认的属性初始化互斥
    发表于 04-02 14:45 232次阅读

    ThreadX(七)------互斥量Mutex

    这里写目录标题概述API二级目录三级目录概述APItx_mutex_createtx_mutex_deletetx_mutex_gettx_mutex_put二级目录三级目录
    发表于 12-28 19:29 8次下载
    ThreadX(七)------互斥量<b class='flag-5'>Mutex</b>

    乱序文件如何重新命名编号

    如下图所示,在本地文件夹中有这样一堆视频文件,在这种情况下并不是乱序的。 但是将其上传到网盘中后,就会经常变成乱序。即它们会按照1、10、11、2、20这样排序,并不方便我们按顺序去依
    的头像 发表于 10-21 10:50 303次阅读
    <b class='flag-5'>乱序文件</b>如何重新命名编号