http://blog.csdn.net/russell_tao/article/details/13092727數據結構
你們知道,所謂線程其實就是「輕量級」的進程。建立進程只能是一個進程(父進程)建立另外一個進程(子進程),子進程會複製父進程的資源,這裏的」複製「針對不一樣的資源其意義是不一樣的,例如對內存、文件、TCP鏈接等。建立進程是由clone系統調用實現的,而建立線程時一樣也是clone實現的,只不過clone的參數不一樣,其行爲也很不一樣。這個話題是很大的,這裏咱們僅討論下TCP鏈接。
在clone系統調用中,會調用方法copy_files來拷貝文件描述符(包括socket)。建立線程時,傳入的flag參數中包含標誌位CLONE_FILES,此時,線程將會共享父進程中的文件描述符。而建立進程時沒有這個標誌位,這時,會把進程打開的全部文件描述符的引用計數加1,即把file數據結構的f_count成員加1,以下:
- static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
- {
- if (clone_flags & CLONE_FILES) {
- goto out;
- }
- newf = dup_fd(oldf, &error);
- out:
- return error;
- }
再看看dup_fd方法:
- static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
- {
- for (i = open_files; i != 0; i--) {
- struct file *f = *old_fds++;
- if (f) {
- get_file(f);
- }
- }
- }
get_file宏就會加引用計數。
- #define get_file(x) atomic_inc(&(x)->f_count)
因此,子進程會將父進程中已經創建的socket加上引用計數。當進程中close一個socket時,只會減小引用計數,僅當引用計數爲0時纔會觸發tcp_close。
到這裏,對於第一個問題的close調用天然有告終論:單線程(進程)中使用close與多線程中是一致的,但這二者與多進程的行爲並不一致,多進程中共享的同一個socket必須都調用了close纔會真正的關閉鏈接。
而shutdown則否則,這裏是沒有引用計數什麼事的,只要調用了就會去試圖按需關閉鏈接。因此,調用shutdown與多線程、多進程無關。