2010-08-28 20 views
11

當一個套接字上的發送/接收正在進行時,套接字是否可以從另一個線程關閉?當同一套接字上的發送/接收正在進行時,是否可以從另一個線程關閉套接字?

假設一個線程阻塞recv調用,另一個線程關閉相同的套接字,recv調用中的線程是否會知道這一點並安全出來?

我想知道不同的操作系統/平臺之間的行爲是否會有所不同。如果是的話,它在Solaris中的表現如何?

回答

2

我不知道Solaris網絡堆棧的實現,但我會拋出我的理論/解釋爲什麼它應該是安全的。

  • 線程A爲給定的套接字輸入一些阻塞系統調用,比如說read(2)。在套接字接收緩衝區中沒有數據,所以線程A從處理器中取出並放入此套接字的等待隊列中。這裏沒有啓動網絡堆棧事件,連接狀態(假設TCP)沒有改變。
  • 線程B在插座上發出close(2)。雖然內核套接字結構應該在線程B訪問它時鎖定,但是沒有其他線程持有該鎖(線程A在進入睡眠等待狀態時釋放該鎖)。假設有插座發送緩衝區沒有出色的數據,一個FIN數據包發送和連接進入FIN WAIT 1狀態(一次我在這裏假設TCP,見connection state diagram
  • 我猜套接字連接狀態變化都將產生一個喚醒所有在給定套接字上被阻塞的線程。那就是線程A會進入可運行狀態並發現連接正在關閉。如果另一方未發送自己的FIN,則可以重新輸入等待,否則系統呼叫將以eof返回。

在任何情況下,內部內核結構都將受到保護,避免不適當的併發訪問。這並不意味着從多個線程執行套接字I/O是一個好主意。我建議查看非阻塞套接字,狀態機和框架,如libevent

0

是的,可以從另一個線程關閉套接字。任何使用該套接字的阻塞/忙線程都會報告一個合適的錯誤。

+6

在linux atleast似乎並沒有像那樣報道。即使我們從另一個線程調用close,阻塞的recv線程仍然被阻塞。 – Jay 2010-09-02 10:42:02

2

對於我來說,關機()從另一個線程插槽做的工作在Linux中

+2

歡迎來到stackoverflow.com。你可以通過提供一些對斷言或提供一個簡短例子的文檔的引用來改進你的答案。 「適合你」的答案沒有幫助,因爲它可能不適用於其他人。 – stefan 2013-05-24 09:39:21

1

如果一個線程被阻塞recv()send()當插座是由不同的線程關閉,被阻塞的線程將收到一個錯誤。但是,收到錯誤後很難檢測到正確的補救措施。這是因爲與套接字關聯的文件描述符編號可能已經被另一個線程拾取,並且被阻塞的線程現在被錯誤喚醒以用於「有效」套接字。在這種情況下,醒來的線程應該是而不是請致電close()本身。

被喚醒的線程將需要一些方法來區分錯誤是否是由連接(例如網絡錯誤)產生的,需要它調用close(),或者錯誤是由其他線程在其上調用close()生成的,在這種情況下,它應該只是在沒有對套接字進行任何操作的情況下出錯。

3

在linux關閉套接字時不會喚醒recv()。此外,作爲@jxh說:

如果一個線程被阻塞的recv()或發送()時,插座是由不同的線程關閉 ,被阻塞的線程將收到一個錯誤。 但是, 收到錯誤後很難檢測到正確的補救措施。這是因爲與該套接字關聯的文件描述符編號 可能已經被另一個不同的 線程拾取,並且現在被阻塞的線程在錯誤時被喚醒爲 「有效」套接字。在這種情況下,喚醒線程本身不應該調用 close()。

的喚醒線程都需要一些方法來區分是否被連接(例如網絡故障),其 需要它來調用close()產生的 錯誤,或者產生差錯由 不同的線程在它上面調用close(),在這種情況下,它應該只是出錯,而不會對套接字做任何進一步處理。

因此避免這兩個問題的最好方法是撥打shutdown()而不是close()shutdown()將使文件描述符仍然可用,因此不會被其他描述符分配,也會喚醒recv()帶有錯誤,並且調用recv()調用的線程可以以正常方式關閉套接字,就像發生正常錯誤一樣。

相關問題