Linux系統編程17 系統調用IO - dup,dup2和原子操作

原子操作:不可分割的操作
原子操作的作用:解決競爭和衝突。
如 tmpnam


程序中的重定向:dup dup2

實驗一:用最土的方法實現 程序的重定向

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

dup2()
newfd 作爲 oldfd的副本,如果 newfd被佔用的話,會先把newfd關閉,再執行文件描述符的拷貝。即 dup2 就相當於 如下兩句的原子操作

close(1); 
dup(fd); 

Note the following points:

   *  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 文件描述符,即標準輸入 輸出 錯誤,但是也可以沒有。如果當前進程默認就沒有標準輸出,那麼上述程序,第一次open 的時候 fd 就會是1 後續程序就是不正確的

情況2:
假如還有一個兄弟進程在跑,當我們 close(1) 的時候,還沒 dup(fd)的時候,如果此時其他與本線程共用一個 文件屬性結構體的指針數組 的進程 open 一個文件,則文件描述符1位置 會被其他文件佔用,則我們這個程序的輸出 會輸出到其他文件,這種情況的原因是如下這兩步操作不原子。

close(1); 
dup(fd); 

實驗3 dup2 原子

#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!");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章