Linuxシステムプログラミング17システムコールIO-dup、dup2およびアトミック操作

アトミック操作:不可分
操作アトミック操作の役割:競争と対立を解決すること。
tmpnamなど


プログラムでのリダイレクト:dup dup2

ファイル記述子の特徴は、現在利用可能な範囲で最小の記述子を使用することを優先することです。

実験1:最も素朴な方法を使用してプログラムのリダイレクトを実現する

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define FNAME "file_echo"

int main()
{
	puts("hello!");//向 文件描述符1 对应的 文件写 
}

その結果、helloが標準出力に出力されます。

次に、コードの最後の行puts( "hello!");を変更せずに、指定されたファイルにhelloを出力するにはどうすればよいですか?

つまり、標準出力が閉じられます。つまり、ファイル記述1の場所が空になり、ファイルが再作成されます。ファイル記述子の特性に従って、使用可能な範囲の最も低い記述子が最初に使用されます。つまり、新しく作成されたファイルのファイル記述子は1です。つまり、標準出力を置き換えると、puts( "hello!");がターゲットファイルに出力されます。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define FNAME "file_echo"

int main()
{
	int fd;
	close(1);//关闭标准输出
	fd = open(FNAME,O_WRONLY|O_CREAT|O_TRUNC,0600);//生成文件,使用文件描述符1
	if(fd < 0)
	{
		perror("open()");
		exit(1);	
	}
	
	puts("hello!");//向 文件描述符1 对应的 文件写 
}


mhr@ubuntu:~/work/linux/sysio/16$ gcc echo.c 
mhr@ubuntu:~/work/linux/sysio/16$ 
mhr@ubuntu:~/work/linux/sysio/16$ ./a.out 
mhr@ubuntu:~/work/linux/sysio/16$ cat file_echo 
hello!
mhr@ubuntu:~/work/linux/sysio/16$ 

名前
dup、dup2、dup3-ファイル記述子を複製します

概要
#include <unistd.h>

   int dup(int oldfd);
   int dup2(int oldfd, int newfd);

説明
dup()システムコールは、新しい記述子に最小番号の未使用記述子を使用して、ファイル記述子oldfdのコピーを作成します。

ファイル記述子をコピーし、使用可能な範囲内の最小のファイル記述子を新しいファイル記述子として使用します。

dup2()
newfdはoldfdのコピーです。newfdが占有されている場合、newfdが最初に閉じられ、次にファイル記述子のコピーが実行されます。つまり、dup2は、次の2つの文のアトミック操作に相当します。

close(1); 
dup(fd); 

Note the following points:

	// 如果 oldfd 不合法,则调用失败,也不会关闭newfd
   *  If oldfd is not a valid file descriptor, then the call fails, and newfd is not closed.

	//如果  oldfd == newfd 则啥也不做
   *  If oldfd is a valid file descriptor, and newfd has the same value as oldfd, then dup2() does nothing, and returns newfd.

実験2はdup()を使用してリダイレクトを実現しますが、欠点はアトミックではありません

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define FNAME "file_echo"

int main()
{
	int fd;
	fd = open(FNAME,O_WRONLY|O_CREAT|O_TRUNC,0600);
	if(fd < 0)
	{
		perror("open()");
		exit(1);	
	}
	
	close(1); //关闭标准输出 1
	dup(fd); // 已知关闭了标准输出,则当前没被使用的最小文件描述符为1,则复制一份文件描述符到 1
	close(fd); //关闭 fd,文件属性结构体中计数器减一,则目前就只剩下 文件描述符1 与 FNAME文件关联了。
	
	puts("hello!"); 
}



mhr@ubuntu:~/work/linux/sysio/16$ gcc dup.c 
mhr@ubuntu:~/work/linux/sysio/16$ ll
total 28
drwxrwxr-x 2 mhr mhr 4096 May  3 02:36 ./
drwxrwxr-x 7 mhr mhr 4096 May  3 02:18 ../
-rwxrwxr-x 1 mhr mhr 8856 May  3 02:36 a.out*
-rw-rw-r-- 1 mhr mhr  329 May  3 02:36 dup.c
-rw-rw-r-- 1 mhr mhr    7 May  3 02:22 file_echo
mhr@ubuntu:~/work/linux/sysio/16$ ./a.out 
mhr@ubuntu:~/work/linux/sysio/16$ cat file_echo 
hello!
mhr@ubuntu:~/work/linux/sysio/16$ 

完了した状況があります。
状況1:
プロセスにはデフォルトで0 1 2のファイル記述子があります。つまり、標準の入力および出力エラーですが、そうでない場合があります。現在のプロセスにデフォルトで標準出力がない場合、上記のプログラムを初めて開いたときのfdは1になり、後続のプログラムは正しくありません。

ケース2:
まだ実行中の兄弟プロセスがあり、close(1)でdup(fd)がまだない場合、この時点でこのスレッドとファイル属性構造のポインター配列を共有している他のプロセスが1つのファイルを開くと、ファイル記述子1の場所は他のファイルによって占有され、プログラムの出力は他のファイルに出力されます。この状況の理由は、次の2つのステップがアトミックではないためです。

close(1); 
dup(fd); 

実験3dup2アトム

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define FNAME "file_echo"

int main()
{
	int fd;
	fd = open(FNAME,O_WRONLY|O_CREAT|O_TRUNC,0600);
	if(fd < 0)
	{
		perror("open()");
		exit(1);	
	}
	
	//close(1);
	//dup(fd);
	dup2(fd,1);
	close(fd);
	
	puts("hello!");
}


mhr@ubuntu:~/work/linux/sysio/16$ 
mhr@ubuntu:~/work/linux/sysio/16$ gcc dup2.c 
mhr@ubuntu:~/work/linux/sysio/16$ ./a.out 
mhr@ubuntu:~/work/linux/sysio/16$ cat file_echo 
hello!
mhr@ubuntu:~/work/linux/sysio/16$ 

しかし、fd自体が1の場合、上記の手順はまだ間違っています

変化する

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define FNAME "file_echo"

int main()
{
	int fd;
	fd = open(FNAME,O_WRONLY|O_CREAT|O_TRUNC,0600);
	if(fd < 0)
	{
		perror("open()");
		exit(1);	
	}
	
	//close(1);
	//dup(fd);
	dup2(fd,1);
	
	if(fd != 1)
		close(fd);
	
	puts("hello!");
}

おすすめ

転載: blog.csdn.net/LinuxArmbiggod/article/details/105905999