原子操作:不可分割的操作
原子操作的作用:解決競爭和衝突。
如 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!");
}