2016-05-16 54 views
-1

除了主執行外,我正在使用兩個線程(pthread_t)的mingw程序中工作。每個線程都包含一個無限循環,用於與外部儀器進行連續通信,每個通信具有不同的速度和協議。主程序僅在用戶請求時在運行時顯示儀器數據。線程中的無限循環只有在main中將「keepalive」變量設置爲0時纔會退出。 要交換線程之間的數據,我想知道的兩種方法,我知道的利弊:與線程共享變量的最佳方式

  • 傳遞參數給線程(一個結構可以使用在pthread_create的最後一個參數傳遞:* arg)。

    int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 
            void *(*start_routine) (void *), void *arg); 
    
  • 使用全局變量和控制併發(的pthread_mutex_lock調用pthread_mutex_unlock

其實我使用兩種方式(主要是因爲我需要一個早期的 「工作程序版本」 )。作爲我參考的變量交易的一個例子:

  1. 我將「keepalive」變量定義爲全局(當線程進入無限循環時共享它)。
  2. 我通過結構傳遞通信配置數據。
  3. 我正在通過全局數組檢索儀器數據(無限循環內更新)
  4. 我正在檢索文件的句柄和與結構體的通信(最後要關閉並釋放一切正常)。

我將不勝感激關於使用全局變量與使用結構與原子變量相關的一些建議。 (代碼清潔,速度,效率,CPU /內存使用...)。

感謝。

+3

避免全局變量,這是一個通用的提示,如果你使用線程也是一樣的。 –

+0

你絕對應該使用原子變量。 – Linus

+0

由於「基於意見」,我看到近距離投票。考慮到這個問題目前的措辭,這可能是事實。改變它以詢問使用全局變量進行線程同步的可能缺點可能會減輕這一點。然後再回答這個問題,我想到這個問題可能會更適合程序員.stackexchange.com,或者? –

回答

0

如果可以的話,儘量避免使用全局變量,因爲它們可能會導致併發性問題,並使代碼難以閱讀。我建議創建一個包含原子類型變量的userdata結構體。類似這樣的:

struct user_data { 
    atomic_bool myBool; 
    atomic_int myInt; 
}; 

int main() { 
    pthread_t myThread; 

    struct user_data userdata = { 
    .myBool = &ATOMIC_VAR_INIT(false), 
    .myInt = &ATOMIC_VAR_INIT(0) 
    }; 
    if (pthread_create(&myThread, NULL, myFunction, &userdata) { 
    // error handling 
    } 
} 

這樣可以避免併發問題並使代碼更具可讀性。 要修改原子變量使用原子操作,如:

atomic_store
atomic_load
atomic_fetch_add

這裏是一個reference原子操作庫。

3

幾乎普遍認爲你不應該使用全局變量。(也是我認爲你可能不理解what extern is for。)

則...

[..]因爲我關心的速度和效率。

您正在利用鎖定來同步訪問。因此,忘掉它,由此引發的開銷會影響其他任何東西。由於(鏈接時間)已知地址,使用全局的潛在的可能「更快」。不過,我認真地懷疑這會有什麼相關性。 請勿在未諮詢探查器的情況下過早進行優化。

全局變量的缺點是它更難測試線程之間的通信。當傳遞struct時,您可以輕鬆啓動另一個線程,並讓該線程與要測試其通信的端點進行通信。您不需要爲此更改任何端點,只需要這些線程啓動的方式即可。

此外,由於類似的原因,它的不容易規模您的應用程序。假設您有兩個線程,例如「搜索者」(用於搜索某些數據)和「索引器」(負責存儲匹配,並可能分離進一步的操作)。如果他們通過一個全局變量進行通信,你將如何添加另一個搜索器線程?您必須使用另一個全局用於新搜索器和索引器之間的通信,複製大部分搜索器線程(所有更改的都是用於通信的變量)。與傳遞包含「溝通渠道」的結構相比:在這裏,您甚至不需要觸摸搜索者代碼,只需啓動另一個。 (雖然索引器必須改變,以便能夠在兩個示例中都有多個輸入源)。

最後,通過線程上的結構傳遞「通信通道」,可以隱藏通信通道,從而限制哪些線程可以訪問它。當試圖找出誰從頻道寫入/閱讀時,這可能非常有價值。 (「寫了那個sh#t的線程是什麼?」)