其他分享
首页 > 其他分享> > 多线程的write和read

多线程的write和read

作者:互联网

对于write和read,由于缓冲区不足或者中断等问题,可能导致读不完或写不完,这也是为什么write和read分别返回的是成功的字节数的原因。所以书中给出了另一种操作readn和writen,保证了读写的完整性,但不保证原子性。

  ssize_t /* Read "n" bytes from a descriptor */
    readn(int fd, void *vptr, size_t n)
    {
        size_t nleft;
        ssize_t nread;

        char *ptr;
        ptr = static_cast<char *>(vptr);
        nleft = n;
        while (nleft > 0)
        {
            if ((nread = read(fd, ptr, nleft)) < 0)
            {
                if (errno = EINTR) //the read is interrupted by signal
                    nread = 0;     //call readn() again
                else
                    return -1; /* error, return amount read so far */
            }
            else if (nread == 0)
            {
                break; /* EOF */
            }
            nleft -= nread;
            ptr += nread;
        }
        return (n - nleft); /* return >= 0 */
    }

    ssize_t /* Write "n" bytes to a descriptor */
    writen(int fd, void *vptr, size_t n)
    {
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;

        ptr = static_cast<char *>(vptr);

        nleft = n;
        while (nleft > 0)
        {
            if ((nwritten = write(fd, ptr, nleft)) <= 0)
            {
                if (nwritten < 0 && errno == EINTR)
                    nwritten = 0; /*call write again */
                else
                    return (-1); /* error */
            }
            nleft -= nwritten;
            ptr += nwritten;
        }
        return (n - nleft); /* return >= 0 */
    }

再探Linux内核write系统调用操作的原子性这篇文章中说了,write和read一次,可以保证是原子操作,因为Linux系统内部是对其上锁了的,同时APUE P63介绍了另一种原子操作pread和pwrite。

下面我们看一下write和read的操作的原子性

1、两个线程分别操作同一个文件。

#include <bits/stdc++.h>
#include <initializer_list>
#include <unistd.h>
#include <functional>
#include <stdio.h>
#include "threadpool/threadpool.h"

#include <unistd.h>
#include<stdio.h>
#include<error.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<iostream>
#include<string.h>
using namespace std;

void test3(string input)
{
   int fd=open("test.txt",O_RDWR);
   //int fd=open("test.txt",O_RDWR|O_APPEND);
   char fa[input.size()+1];

    strcpy(fa,input.c_str());


   int num=write(fd,fa,strlen(fa));//这里写的是fa长度
   
   cout<<"write number: "<<num<<endl;
   close(fd);

}


int main()
{
    threadpool::ThreadPool tt;//线程池

    string s1(2000000,'1');
    string s2(2000000,'2');
    
    tt.AddTask(test3,s1);
    tt.AddTask(test3,s2);

    getchar();
    return 0;

}


(1)直接写

int fd=open("test.txt",O_RDWR);

要么全是1,要么全是2

(2)追加写

int fd=open("test.txt",O_RDWR|O_APPEND);

要么是1111…22222,要么是22222…11111,不会出现交错

总结1

对于文件描述符,映射到Linux同一个文件指针,write和read都是原子操作

2、两个线程分别操作同一个文件描述符。

效果和上面情况类似

标签:include,read,write,fd,nleft,多线程,ptr
来源: https://blog.csdn.net/weixin_43353102/article/details/118861945