Linux system programming 17 system call IO-dup, dup2 and atomic operation

Atomic operations: indivisible
operations The role of atomic operations: to resolve competition and conflict.
Such as tmpnam


Redirection in the program: dup dup2

The feature of file descriptors is to give priority to using the smallest descriptor in the currently available range

Experiment 1: Use the most earthy method to achieve program redirection

#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 对应的 文件写 
}

The result is to print hello to standard output!

Then, without changing the last line of code puts("hello!");, what should I do to output hello to the specified file?

That is, the standard output is closed, that is, the location of file description 1 is vacated, and a file is re-created. According to the characteristics of the file descriptor, the lowest descriptor in the available range is used first, that is, the file descriptor of the newly created file is 1. That is, replace the standard output, then puts("hello!"); will be output to the target file.

#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$ 

NAME
dup, dup2, dup3-duplicate a file descriptor

SYNOPSIS
#include <unistd.h>

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

DESCRIPTION
The dup() system call creates a copy of the file descriptor oldfd, using the lowest-numbered unused descriptor for the new descriptor.

Copy the file descriptor and use the smallest file descriptor in the available range as the new file descriptor.

dup2()
newfd is a copy of oldfd. If newfd is occupied, newfd will be closed first, and then the file descriptor copy will be executed. That is, dup2 is equivalent to the atomic operation of the following two sentences

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.

Experiment 2 uses dup() to achieve redirection, disadvantage: not atomic

#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$ 

There is a completed situation:
Situation 1:
A process has 0 1 2 file descriptors by default, that is, standard input and output errors, but they may not. If the current process does not have standard output by default, then the fd of the above program will be 1 when it is opened for the first time. The subsequent programs are incorrect.

Case 2:
If there is still a sibling process running, when we close(1) and there is no dup(fd) yet, if at this time other processes sharing a pointer array of file attribute structure with this thread open one File, the file descriptor 1 location will be occupied by other files, and the output of our program will be output to other files. The reason for this situation is that the following two steps are not atomic.

close(1); 
dup(fd); 

Experiment 3 dup2 atom

#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$ 

But if fd itself is 1, the above procedure is still wrong

change

#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!");
}

Guess you like

Origin blog.csdn.net/LinuxArmbiggod/article/details/105905999