簡體   English   中英

嘗試退出阻塞的UDP套接字讀取

[英]Trying to exit from a blocking UDP socket read

這是一個類似於關閉阻塞UDP套接字的正確方法的問題。 我在C中有一個線程,它從UDP套接字讀取。 讀取是阻止的。 我想知道是否有可能退出線程,而不依賴於recv()返回? 例如,我可以從另一個線程關閉套接字並安全地期望套接字讀取線程退出嗎? 在那個帖子上沒有看到任何高投票的答案,這就是為什么我再次問它。

這實際上取決於您正在運行的系統。 例如,如果您在符合POSIX的系統下運行且線程可取消,則取消線程時recv()調用將被中斷,因為它是取消點。

如果您正在使用較舊的套接字實現,您可以為您的線程設置SIGUSR1之類的信號處理程序,並希望沒有其他人想要它並發出信號,因為recv()將中斷信號。 如果可能的話,你最好的選擇是不要阻止。

我不認為關閉阻塞操作中涉及的套接字是終止操作的安全保證方式。 例如, kernel.org黑暗警告:

關閉文件描述符可能是不明智的,因為它們可能在同一進程中的其他線程中被系統調用使用。 由於文件描述符可能被重用,因此存在一些可能導致意外副作用的模糊競爭條件。

  • 相反,您可以使用信號並使用EINTR使recv失敗(確保未啟用SA_RESTART )。 您可以使用pthread_kill向特定線程發送信號

  • 您可以在啟動recv調用之前在套接字上啟用SO_RCVTIMEO

就個人而言,我通常會試圖避開所有信號的骯臟,但這是一個可行的選擇。

你有幾個選擇。 信號將中斷讀操作,因此您需要做的就是確保信號熄滅。 recv操作應該失敗,錯誤號為EINTR。

最簡單的選擇是設置一個計時器,在一些超時后中斷你自己的進程,例如30秒:

itimerval timer
timeval time;
time.tv_sec = 30;
time.tv_usec = 0;
timer.it_value = time;
if( setitimer( ITIMER_REAL, &timer, NULL ) != 0 )
  printf( "failed to start timer\n" );

您將在指定時間后獲得SIGALRM,這將中斷您的阻止操作,並讓您有機會重復操作或退出。

當另一個線程正在或可能正在使用共享資源時,您無法釋放共享資源。 在實踐中,您會發現您甚至無法編寫代碼來執行您的建議。

想一想。 當你打電話給close ,你怎么可能知道另一個線程實際上在recv被阻止了? 如果要調用recv ,然后另一個線程調用socket並獲取剛剛關閉的描述符,該怎么辦? 現在,不僅該線程沒有檢測到任何錯誤,而且它將在錯誤的套接字上調用recv

可能有一種很好的方法來解決您的外部問題,這是您需要退出阻塞UDP套接字讀取的原因。 還有幾個丑陋的黑客可用。 基本方法是使套接字無阻塞,而不是阻塞UDP套接字讀取,偽造帶有selectpoll的阻塞讀取。 然后,您可以通過以下幾種方式中止此循環:

一種方法是select超時並在select返回時檢查'abort'標志。

另一種方法是在管道的讀取端select 將單個字節發送到管道以中止select

如果是posix complient系統,你可以嘗試監視你的線程: pthread_create ,其功能使你的recvpthread_cond_signal緊隨其后,然后返回。
調用線程使用所需的超時生成pthread_cond_timedwait ,並在timed_out時終止被調用的線程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM