V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
1YsX1
V2EX  ›  C++

请教一个简单的 C++并发文件写入冲突的问题。

  •  
  •   1YsX1 · 2020-10-11 18:31:12 +08:00 · 2591 次点击
    这是一个创建于 1511 天前的主题,其中的信息可能已经有所发展或是发生改变。

    写了一个简单的 demo 来测试单文件的并发写入,给每个位置写且仅写一次不同的数字,我觉得这个场景貌似是不包含冲突的问题的,因为访问的文件地址都不一样的。但是实际结果确实是产生冲突了。希望有大佬有时间进行指教,谢谢!
    代码如下

    #include <iostream>
    #include <unistd.h>
    #include <pthread.h>
    #include <stdint.h>
    
    using namespace std;
    
    FILE *fp;
    
    void * running(void * args){
        uint8_t* pos = (uint8_t *)args;
        FILE * nowfp = fp;
        fseek(nowfp,*pos,SEEK_SET);
        fwrite(pos,1,1,nowfp);
        delete pos;
        return 0;
    }
    
    int main(int,char **){
        fp = fopen("test.bin","wb+");
        pthread_t t_a;
        for(int i =0;i<100;i++){
            uint8_t* j = new uint8_t(i);
    	    pthread_create(&t_a,NULL,running,j);
        }
        while (true)
        {
            sleep(1000);
        }
        return 0;
    }
    

    程序输出结果如下 除了第一个位置以外,有很多值为 0 的点。不太明白这个并发冲突产生在哪里。:

      Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 	
    00000000: 00 00 02 03 01 00 00 07 08 04 0A 0B 0C 0D 0E 0F    ................
    00000010: 10 11 12 13 2F 15 16 17 18 19 1A 1B 00 1D 1E 1F    ..../...........
    00000020: 20 21 22 23 00 25 26 40 28 00 2A 2B 2C 2D 2E 00    .!"#.%&@(.*+,-..
    00000030: 30 31 32 33 34 35 36 37 00 39 3A 3B 00 3D 3E 3F    01234567.9:;.=>?
    00000040: 00 41 42 43 44 45 46 47 3C 48 00 4B 4C 4D 4E 4F    .ABCDEFG<H.KLMNO
    00000050: 50 51 52 53 54 55 56 57 58 59 00 5B 5C 5D 5E 5F    PQRSTUVWXY.[\]^_
    00000060: 60 61 62 63                                        `abc
    
    
    12 条回复    2020-12-02 00:53:12 +08:00
    ho121
        1
    ho121  
       2020-10-11 18:42:24 +08:00 via Android
    fwrite 执行之前被其它线程 fseek 改掉了位置
    qianlv7
        2
    qianlv7  
       2020-10-11 18:44:12 +08:00
    用 pwrite,FILE* 共享了位移
    qianlv7
        3
    qianlv7  
       2020-10-11 18:45:13 +08:00
    文件偏移共享了,导致冲突
    1YsX1
        4
    1YsX1  
    OP
       2020-10-11 18:53:07 +08:00
    @ho121
    @qianlv7
    fseek 操作的是一个临时变量 nowfp 而不是全局变量 fp,这样也会有冲突??
    geelaw
        5
    geelaw  
       2020-10-11 18:58:19 +08:00   ❤️ 1
    @1YsX1 #4 这是双重理解错误。

    1. FILE * 实际起效果的是“被指向的” FILE 结构,而不是 FILE * 本身,复制指针的值并不会复制 FILE 结构,因此操作的是同一个 FILE 。
    2. fseek 传入的参数是 FILE * 而不是 FILE *&,并不存在“操作传入的变量”这种说法,它获得的永远是传入值的副本。把 fp 复制到 nowfp 再传入是多此一举,不会有任何效果。
    user8341
        6
    user8341  
       2020-10-11 19:04:07 +08:00
    FILE 里面有文件描述符。文件描述符只是一个数组下标而已。数组“打开文件表”是操作系统维护的,所有进程共享的。
    ho121
        7
    ho121  
       2020-10-11 19:21:35 +08:00 via Android
    @1YsX1 变量是不同的,但它们指向的对象是一个对象(指针地址一样)
    1YsX1
        8
    1YsX1  
    OP
       2020-10-11 20:08:35 +08:00
    @geelaw
    @user8341
    @ho121
    谢谢各位的指点!我明白了!!
    abutter
        9
    abutter  
       2020-10-12 08:39:09 +08:00
    man 2 flock
    jedihy
        10
    jedihy  
       2020-10-12 09:52:43 +08:00
    哈哈,楼主是不是原来写 js 的?
    Testlinuxtous
        11
    Testlinuxtous  
       2020-10-24 03:34:48 +08:00 via iPhone
    @abutter 能给一个邮箱交流一下吗?
    weiqk
        12
    weiqk  
       2020-12-02 00:53:12 +08:00 via Android
    加锁,这个问题在 win 上应该不存在,在 unix 系统上肯定有
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2639 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 10:55 · PVG 18:55 · LAX 02:55 · JFK 05:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.