题目

 编写一个程序,最多可接收3个命令行参数:

$ ./5-3 filename num-bytes [-x]

该程序打开指定的文件,然后每次写入一个字节的方式,向尾部追加num-bytes字节。缺省情况下,打开文件的标志应有O_APPEND,但若存在第三个命令行参数,那么就使用lseek到文件末尾再进行写入。最后运行这两个命令查看结果:

./5-3 f1 1000000  & ./5-3 f1 1000000 

./5-3 f1 1000000 -x & ./5-3 f1 1000000 -x

代码

#include <ctype.h>
#include "tlpi_hdr.h"
#include <stdbool.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
char ch;
char byte='a';
bool x = FALSE;
int fd=-1,cnt;
/* 读取选项 */
if (argc < 3)
{
usageErr("filename num-bytes [-x]\n");
exit(EXIT_SUCCESS);
}
while ((ch = getopt(argc, argv, "x")) != -1)
{
switch (ch)
{
case 'x':
printf("have x\n");
x = TRUE;
break;
default:
usageErr("filename num-bytes [-x]\n");
break;
}
}

if (x)//有x的情况
{
//当判断到了-x后,参数会被重新排列
cnt=atoi(argv[3]);
byte='x';
//改成lseek来调整
fd=open(argv[2],O_RDWR | O_CREAT , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if(fd==-1)
{
errExit("open");
}
while(cnt)
{
lseek(fd,0,SEEK_END);
write(fd,&byte,1);
cnt--;
}
}else
{
cnt=atoi(argv[2]);
//只写 追加 证明了O_APPEND是原子操作,使用时不会受多线程的影响
fd=open(argv[1],O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if(fd==-1)
{
errExit("open");
}
while(cnt)
{
write(fd,&byte,1);
cnt--;
}
}

exit(EXIT_SUCCESS);
}

结果

  • 不带-x参数

    $ ./5-3 f1 1000000 & ./5-3 f1 1000000 
    $ ls -lh f1
    -rw-rw-r-- 1 zqh zqh 2.0M 5月 9 10:38 f1

  • 带-x参数

    $ ./5-3 f1 1000000 -x & ./5-3 f1 1000000 -x
    $ ls -lh f1
    -rw-rw-r-- 1 zqh zqh 1010K 5月 9 10:46 f1
  • 总结

     使用O_APPEND参数打开的文件属于原子操作,两个不同的进程对一个文件做输入,是不可分割的操作  使用lseek操作,不属于原子操作。

扩展

 我尝试修改了这个程序名为5-3.1,并且查看结果 | | 原程序 | 新程序 | |-- |----------|----------| |无 -x |写入a |写入b | |有 -x |写入x |写入y |

  • 不带-x参数