2014-04-01 74 views
2

這裏我有一些問題,當在多線程案例中使用打開pthread_cancel()。在線程中,我需要打開一些文件來閱讀。如何知道文件描述符是否打開?

所以我的第一個問題是,我是否需要附上我使用那些打開的文件描述符pthread_cleanup_push()pthread_cleanup_pop()的字段。我認爲,如果線程被取消,文件仍然打開,它不會好。

但是,據我所知,open()函數本身是一個可能的取消點。並且我不知道是否打開文件描述符(如果發生取消)(或者我可以從哪裏獲得該文件的信息?)

最後,是否有一個Unix接口來告訴文件描述符是否打開還是不打開?

回答

2
  1. 是的,使用pthread_cleanup_push()是一個好主意。

  2. 如果線程在open()中被取消,則文件描述符將不會打開,因此清理代碼只需關閉先前打開的任何內容。

  3. 您可以使用fstat()來檢查文件描述符是否打開。或者,您可以使用將文件描述符作爲參數的其他函數之一,如果描述符未打開,則查找EBADF(錯誤文件描述符)。 fstat()的優點在於它是一個純粹的詢問函數,而大多數人試圖改變關於描述符的內容。 fcntl()也可以查詢。

+0

你確定*如果取消在'open'中發生,文件描述符保證不會被打開?我在POSIX中看到的唯一可以做出這種保證的語言是「在函數調用期間暫停取消請求時的行爲的副作用與在單線程中可能出現的副作用相同程序當一個函數的調用被一個信號中斷,並且給定的函數返回[EINTR]「,並且我不相信'open'不會在EINTR失敗時不打開文件(*不管*標準在這一點上說)。 – zwol

+0

直到open()調用成功返回,文件描述符纔會打開,就是說它不是取消點。應用程序無法知道將要返回哪個文件描述符(好吧,它有順序分配,當前打開的最低文件描述符屬性,但在多線程應用程序中很難確定)。所以,必須由內核來跟蹤事情,直到open()成功返回。 –

+0

我想象中的特定場景(如果不是徹底違反合規性,這將成爲C庫中的QoI錯誤,但這是我可以輕易想象的現存錯誤)是檢查取消立即發生在系統調用返回到用戶空間之後 - 在一個或兩個指令中,在libc存根返回之前。因此,就內核而言,系統調用成功並且文件處於打開狀態,但在取消線程之前,應用程序沒有機會對其執行任何操作。 – zwol

1

是的,如果一個線程可以同時擁有的唯一參考打開文件描述符被取消,則需要使用pthread_cleanup_push/pop,以確保它們關閉;否則會泄漏。

事實上,open函數本身就是一個取消點,其他幾個資源分配函數(這裏是a complete list of cancellation points)也是如此。標準中有語言可以讀取,要求文件而不是已被打開,但如果取消發生在open,但我不相信實現已經得到了正確的結果。處理此問題的唯一100%可靠方法是使用pthread_setcancelstate在打開文件(或分配其他資源)時禁用取消,並僅在後續的pthread_cleanup_push後重新啓用它。

可以通過查看無操作fcntl是否失敗並將errno設置爲EBADF來判斷文件描述符是否打開,但不要執行此操作。它本質上是一種迴旋 - 在檢查和代碼控制之間 - 依賴於檢查,另一個線程可能會重複使用該文件描述符編號,並且程序可能會行爲不當,可能是災難性的(例如覆蓋錯誤的文件)。

+0

你確定這次墜機事件嗎?內核應該避免線程在彼此的腳趾上太猛烈地跳躍並導致崩潰。如果一個線程在另一個線程讀取時讀取另一個線程,則其中一個線程會失敗並顯示錯它不應該是一個崩潰。如果另一個線程在你的代碼檢查它被關閉並被告知它被關閉以及你採取行動的時間之間打開一個文件描述符......這取決於你在做什麼。如果你對被關閉的描述符執行'dup2()'操作,這意味着另一個線程不會寫入它認爲是的文件,但是......這不應該是崩潰。 –

+0

@JonathanLeffler是的,'崩潰'可能太強大了 - 我正在考慮'其他線程沒有寫入它認爲是'場景的文件。另一方面,覆蓋錯誤的文件往往比崩潰更糟糕。 – zwol

+0

同意混淆什麼文件描述符正在處理什麼文件是壞的,但我想這取決於他們所做的一切。我認爲這個建議必須要小心'dup2()和它的'fcntl()'對應。大多數其他的文件描述符生成調用(如果您曾經使用過,則使用'open()','socket()','opendir()','creat()'等)來生成文件描述符,並確保新文件描述符是唯一的在這個過程中。當然'文件描述符N在線程1中被關閉,並且在線程2中的一個打開的問題被重新分配。但進程應該知道哪些文件描述符是打開的。 –

相關問題