2011-05-16 111 views
2

我有一個線程可以鎖定互斥鎖,將值寫入變量,解鎖互斥鎖。 我在這裏打印出來並且值已經改變了。我將它設置爲1。線程同步

當我使用鎖定,解鎖互斥和讀出的值在另一個線程讀取的變量值,我得到的0

舊值爲什麼會發生這種情況。我正確鎖定和解鎖相同的互斥鎖。

如何同步線程?

編輯:

我宣佈互斥,在這裏變量

static pthread_mutex_t movementIdMutex = PTHREAD_MUTEX_INITIALIZER; 
static int nav_movementId = 0; 

static pthread_mutex_t newMovementMutex = PTHREAD_MUTEX_INITIALIZER; 
static int nav_newMovement = 0; 

我這裏

void nav_setMovementIdentifier(int id) 
{ 
printf("Received movement id:%d from connectivity\n", id); 

int result; /* Use the result for testing */ 

result = pthread_mutex_lock(&movementIdMutex); 
nav_movementId = id; 
printf("nav_movementId is %d\n", nav_movementId); 
result = pthread_mutex_unlock(&movementIdMutex); 

result = pthread_mutex_lock(&newMovementMutex); 
nav_newMovement = 1; 
printf("nav_newMovement is %d in the setId function\n", nav_newMovement); 
result = pthread_mutex_unlock(&newMovementMutex); 
printf("\n"); 
} 

設置變量,並在這裏閱讀他們

void *startConnectivityListener(void *ptr)  { 

/* Declare safety variables because segments cant be locked/unlocked 
* using mutexes if they are checking in statement such as if and while. 
*/ 
int newMoveCheck = 0; 
int startIndoorCheck = 0; 
int startOutdoorCheck = 0; 

int listening = 1; 

while(listening == 1) 
{ 
    int result; /* Use for testing */ 

    /* check if a new movement command waits */ 
    result = pthread_mutex_lock(&newMovementMutex); 
    newMoveCheck = nav_newMovement; 
    printf("nav new movement in thread is :%d\n", nav_newMovement); 
    printf("newMoveCheck in mutex lock is:%d\n", newMoveCheck); 
    result = pthread_mutex_unlock(&newMovementMutex); 

    result = pthread_mutex_lock(&movementIdMutex); 
    printf("nav_movementId in thread is %d\n", nav_movementId); 
    result = pthread_mutex_unlock(&movementIdMutex); 

    printf("newMoveCheck is %d\n", newMoveCheck); 
    sleep(1); 

    if(newMoveCheck == 1) 

我得到的正確的pri在setter函數printf語句中,它將值設置爲傳入並且設置爲1的id。

當我嘗試打印它時,我仍然在讀取它們,它們仍然顯示0,這是它們被設置爲當我初始化他們。

+0

需要查看一些代碼,以便我們可以知道問題的出現位置 – 2011-05-16 15:36:34

+2

您能否提供可複製問題的可編譯示例? – janneb 2011-05-16 15:37:31

+0

我加了相關的代碼。 :) – jarryd 2011-05-16 15:48:17

回答

0

這些聲明:

static int nav_movementId = 0; 
static int nav_newMovement = 0; 

創造全新的,不同的變量 - 這就是爲什麼你看不到修改的全局變量。作出聲明,像這樣如此作用於全球的情況下,多數民衆贊成更新變量的函數:

extern int nav_movementId; 
extern int nav_newMovement; 

同樣,互斥需要是相同的情況 - 他們需要的是全局或者你需要安排得到他們的地址在模塊之間共享。

在一個模塊:

pthread_mutex_t movementIdMutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_mutex_t newMovementMutex = PTHREAD_MUTEX_INITIALIZER; 

在報頭(或其它模塊):

extern pthread_mutex_t movementIdMutex; 
extern pthread_mutex_t newMovementMutex; 
+1

變量和互斥體在.c文件中聲明,並且所有線程代碼都在同一個文件中。所以理論上這些變量應該適用於所有的線程。靜態互斥變量是否也是不同的副本?應該做什麼?我應該刪除互斥鎖和變量的靜態聲明嗎? – jarryd 2011-05-16 17:16:21

+0

如果代碼在其自己的進程中運行,它包含作爲另一個進程的一部分的.h文件或corelogic.c會怎麼樣?我有一個進程運行一堆代碼,其中包含在另一個進程中運行的模塊的頭文件。過程1中的代碼調用過程2中的代碼並設置存在於過程2中的代碼中的變量?進程1是否具有通過.h文件連接的所有代碼的副本,它包含進程2的模塊?所以有兩個變量副本,每個進程有1個副本?是否不可能從流程1中設置流程2的變量? – jarryd 2011-05-16 17:37:21

+0

如果你是在說「corelogic。c「包含在多個可執行映像中,並且/或者您運行的是同一個可執行文件的多個副本,那麼答案是:每個正在運行的進程都有一個變量副本,您不能在進程之間共享內存通過在每一箇中聲明相同的變量 – AShelly 2011-05-16 17:54:20

0

那些是靜態互斥和變量相同的源文件,如下的代碼,或者是他們在頭上?如果它們位於標題中,並且這兩個函數位於不同的文件中,則每個函數都有自己的互斥量和變量副本。您需要使它們變爲extern而不是static.

另一件事:「偵聽器」函數實際上並未等待其他函數設置變量 - 互斥量僅確保它們未被主動寫入。因此,如果您第一次在聽衆中讀取​​,它仍然爲0,我不會感到驚訝。關於您希望系統如何工作的更多解釋可能對此有所幫助。

+0

系統應該工作的方式是模塊corelogic.c具有所有變量,互斥體,線程代碼。其他模塊導入頭文件,以便他們可以使用這些函數來設置變量值。我有幾個線程被啓動,其中一個讀取從我提到的函數調用中設置的變量的值。問題在於變量在設置時正在更新,但在讀取時未顯示更新的值。我懷疑有2組這樣的變量或者其他東西,2個副本。 – jarryd 2011-05-16 17:12:56

+0

請注意,printf被緩衝,並且不完全是線程安全的。您可能無法按照發生的順序獲得打印件。讀者是否在循環? - 它看起來像它,但代碼不完整。如果直到閱讀器循環啓動後才寫入作者,我希望在看到「1」之前看到幾個「newMoveCheck爲0」。如果這是在第一個「1」上退出的測試代碼,那麼您可能根本看不到最終的printf。 – AShelly 2011-05-16 17:30:49

+0

請看我對Michael的回答的第二個評論。 – jarryd 2011-05-16 17:49:54

0

線程執行順序是不確定的,這意味着僅僅因爲你已經啓動了線程並不意味着線程的執行順序將按照你啓動它們的順序。爲了同步線程,你必須創建「障礙」,這是代碼中的一個點,一個線程無法繼續直到另一個線程到達特定點。這通常是用信號量來完成的,儘管你可以通過互斥和條件變量來完成。

這個概念是,如果你有兩個線程和兩個信號量,當另一個線程正在運行時,可以導致一個線程阻塞。然後當第一個線程完成運行時,它將解除第二個線程的阻塞,第二個線程阻塞第一個線程。當一個線程阻塞而另一個線程工作時,這可以繼續重複,反之亦然。因此,步驟爲:

  1. 線程#1初始化信號#1鎖定,信號#2解鎖
  2. 線程#1的發射線#2,然後鎖定信號#2,並繼續對
  3. 同時線#1試圖鎖定已鎖定信號#1,所以阻塞而線程#2的作品坐鎮
  4. 線程#2結束,解鎖信號#1 ...線程#1,現在仍在繼續
  5. 主題#2試圖鎖定信號量#2,但它被鎖定,所以它必須等待線程#1完成工作
  6. 線程#1完成的工作,並解鎖信號#2 ......線程#2現在繼續
  7. 線程#1試圖鎖定信號#1,但它是鎖着的,所以它必須等待線程#2完成工作
  8. 不斷重複,直到你達到一定終止條件...

所以基本上線#1解鎖線程#2,反之亦然。線程#1不會自己解鎖,然後鎖定線程#2,或者其他一些線程必須同時爲自己和另一個線程鎖定和解鎖信號量的其他變體。這樣你就不會有一個「交叉」點,在這個點上線程沒有被鎖定,並且它們都是空閒的,或者更糟糕的是,兩個線程都在等待另一個線程解鎖自己的死鎖狀態。

通過使用信號量,您可以在您的應用程序中有效地創建「障礙」,這將允許線程運行方式具有某種程度的確定性,並創建彼此同步的線程。你將能夠確定地說一個線程不能繼續超過某個點,直到另一個線程到達某個點......因此你的同步點是使用信號量的固有特性創建的。

1

嘗試將volatile說明符添加到nav_movementId和​​變量。

+0

最終問題在於進程本身是分叉的,所以它們是在自己的進程中運行的程序的兩個對應,一個是更新它自己的變量,另一個是讀取它自己的,未更新的變量。在打印內存地址時,它們基於在分叉進程之前創建的虛擬內存地址相同。奇怪的設置:P – jarryd 2011-05-18 15:17:19