原子操作与程序中的重定向: dup()与dup2()函数

程序中的重定向: dup()与dup2()函数


原子操作

不可分割的操作
原子:不可分割的最小单位
原子操作的作用:就是解决竞争和冲突
tmpname就不是一个原子操作
多用于多进程和多线程并发的时候


一、dup()函数

dup函数作用:

dup用来复制参数oldfd所指的文件描述符。

头文件及函数定义:
#include <unistd.h>
int dup(int oldfd);

dup函数创建一个新的文件描述符,该新文件描述符和原文件描述符指向相同的文件、管道、或网络连接,dup返回的新文件描述符是取系统当前可用的最小整数值(一般情况下系统默认了标准输入0、标准输出1、标准出错2,在没有其他文件描述符的情况下,文件描述符fd的值为3,那么首次调用dup函数的返回值为4(3+1))
dup调用失败时都返回-1并设置errno
调用dup(oldfd)等效于
fcntl(oldfd, F_DUPFD, 0)

dup函数会使用当前可用范围内最小的文件描述符作为新的描述符,拷贝一个副本放到当前可用范围内最小的位置上去。
比如:如果原来有个4号文件描述符,0~5都被用上了,执行dup,把这个4号复制一份,当前可用范围内最小的就是6号,所以会把4号的一个副本放到6号,4号和6号指向的是同一个结构体。

代码演示

要求;将本要输出到屏幕上的hello!输出到指定的文件上
思路:输出到屏幕使用的是标准输出,标准输出的文件描述符是1,故我们可以对1做一个重定向

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <sys/types.h>
  5 #include <sys/stat.h>
  6 #include <fcntl.h>
  7 #include <unistd.h>
  8 int main()
  9 {
 10   int ps;
 11   ps=open("temp",O_RDWR|O_CREAT|O_TRUNC,0644);
 12   close(1);//关闭标准输出的文件描述符等于关闭了标准输出                                                                             
 13   dup(ps);//将temp文件描述符重定向到1号文件描述符
 14                                 
 15 /**********禁止修改************/                                 
 16   puts("hello!");//puts调用的就是1号描述符,1号描述符默认是stdout
 17   exit(0);
 18 }
~

上面代码的默认1是标准输出,但是有的时候1不一定是标准输出,或者如果没有1号,就会出错。如果是多进程或是多线程的时候,当我们close(1)时,还没来得及dup,有可能有别的进程或是线程先使用了1号,就会让puts输出到别的文件上去。所以我们可以使用dup2来避免上述问题
下面的两句不是原子操作

 12   close(1);//关闭标准输出的文件描述符等于关闭了标准输出                                                                             
 13   dup(ps);//将temp文件描述符重定向到1号文件描述符

dup2:dup2就可以实现原子化操作
dup2可以理解为close和dup的原子操作
所以上面的代码那两句话,可以使用dup2代替dup2(fd,1);

二、dup2()函数

函数功能:用来复制一个文件描述符

 #include <unistd.h>
 int dup2(int oldfd, int newfd);

dup2与dup区别是dup2可以用参数newfd指定新文件描述符的数值。若参数newfd已经被程序使用,则系统就会将newfd所指的文件关闭,若newfd等于oldfd,则返回newfd,而不关闭newfd所指的文件。dup2所复制的文件描述符与原来的文件描述符共享各种文件状态。共享所有的锁定,读写位置和各项权限或flags等.
返回值:若dup2调用成功则返回新的文件描述符,出错则返回-1.

代码演示

使用dup2 代替dup:原子操作

 1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <sys/types.h>
  5 #include <sys/stat.h>
  6 #include <fcntl.h>
  7 #include <unistd.h>
  8 int main()
  9 {
 10   int ps;
 11   ps=open("temp",O_RDWR|O_CREAT|O_TRUNC,0644);
 12  // close(1);//关闭标准输出的文件描述符等于关闭了标准输出
 13  // dup(ps);//将temp文件描述符重定向到1号文件描述符
 14   dup2(ps,1);
 15   if(ps!=1)//新文件和旧文件的文件描述符不一样 则重定向成功,我们可以关闭旧的文件描述符
 16     close(ps);                                                                                                                      
 17 /**********禁止修改************/
 18   puts("hello!");//puts调用的就是1号描述符,1号描述符默认是stdout
 19   exit(0);
 20 }

如果fd本来就是1,那么dup2就不做什么,还是保持原状,如果fd不为1则将其重定向为1,并关闭fd本身的文件描述符


总结

同步(sync,fsync,fdatasync):

sync();
---------- commit buffer cache to disk(同步buffer和cache,内核层面的)

也可以叫做全局催促,什么时候会用到全局催促,解除设备挂载(关机)的时候。
比如说当前的内核在即将关机的时候,需要把当前的正在cache当中的或者buffer还没有来得及同步的数据刷新一下。这个时候就可以用sync
然后下一步解除设备挂载

fsync;
#include <unistd.h>

   int fsync(int fd);//同步一个文件的buffer或者是cache

int fdatasync(int fd);//同步一个文件,只刷数据不刷亚数据
数据:文件当中的有效内容
亚数据:文件最后的修改时间,文件的属性等等这些内容。

fcntl();

文件描述符所变的魔术几乎都来源于该函数(管家级的函数

fcntl - manipulate file descriptor(管理文件描述符

#include <unistd.h>
#include <fcntl.h>
 int fcntl(int fd, int cmd, ... /* arg */ );

ioctl();

设备相关的内容都归这个函数管

   #include <sys/ioctl.h>
   int ioctl(int fd, unsigned long request, ...);

虚目录:/dev/fd目录

显示的是当前进程的文件描述符信息

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式学习~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值