2017-04-07 85 views
1

我很難理解如何在使用信號量的兩個進程之間交替控制。這是流程處理代碼的一個人爲的例子。使用信號量同步進程

int pid = fork(); 

if (pid) { 
    int counter = 0; 
    while (true) { 
    counter += 1; 
    printf("P%d = %d", pid, counter); 
    } 
} else { 
    int counter = 0; 
    while (true) { 
    counter += 1; 
    printf("P%d = %d", pid, counter); 
    } 
} 

我期待上面的代碼並行運行,但它似乎是控制流繼續爲即時分叉過程,後來才恢復父進程。

這是從根本上打破了使用信號來控制哪些程序可以充當我現有的代碼。

int id = get_semaphore(1); 
int pid = fork(); 

if (pid) { 
    int counter = 0; 
    while (true) { 
    sem_wait(id); 
    counter += 1; 
    printf("P%d = %d\n", pid, counter); 
    sem_signal(id); 
    } 
} else { 
    int counter = 0; 
    while (true) { 
    sem_wait(id); 
    counter += 1; 
    printf("P%d = %d\n", pid, counter); 
    sem_signal(id); 
    } 
} 
  • sem_wait的輔助剛剛從信號量的值和塊直到結果減去1> 0(使用semop罩下)。

  • sem_signal輔助只是增加了1到信號量的值(發動機罩下使用semop)。

我想代碼以兩個過程之間交替,使用sem_wait阻止,直到其他過程與sem_signal釋放資源。所期望的輸出將是:

P1 = 0 
P0 = 0 
P1 = 1 
P0 = 1 
... 

然而,由於過程之間的初始執行延遲,子過程需要可用的信號量的資源,用它來打印數,則其恢復和循環 - 在該點該資源再次可用,因此它不會等待其他進程。

什麼是防止利用資源的過程,如果他們釋放自己的最好方法?

+0

您需要兩個信號量和一個「executeNow」單元。在進程之間來回傳遞單元。 – ThingyWotsit

回答

1

信號燈有兩種通用的用例。一個是互斥,另一個是同步。你的代碼做了什麼是互斥。你真正想要的是父進程和子進程之間的同步(交替)。

讓我解釋一下:
互斥意味着在任何時候只有一次進程可以訪問一個「臨界區」,這是你要只有一個進程/線程在time.Critical訪問的一段代碼部分通常具有操作共享資源的代碼。

來到你的代碼,因爲您僅使用一個單一的信號,也不能保證,以作爲對於每一個進程被允許進入臨界區的「秩序」。 例如:您的代碼中的sem_wait(id)可以由任何進程執行,並且兩個進程之間不必交替。

進程同步(更具體的交替),您需要使用兩個信號之一父母和其他兒童。

Sample code: 
    int pid = fork(); 

    int parent_sem = get_semaphore(0); 
    int child_sem = get_semaphore(1); 

    if (pid) { 
     int counter = 0; 
     while (true) { 
      sem_wait(child_sem); 
      counter += 1; 
      printf("P%d = %d", pid, counter); 
      sem_signal(parent_sem); 
     } 
    } else { 
     int counter = 0; 
     while (true) { 
      sem_wait(parent_sem); 
      counter += 1; 
      printf("P%d = %d", pid, counter); 
      sem_signal(child_sem); 
     } 
    } 

需要初始化一個信號(在我的情況的孩子)1,第二個零。這樣,只有兩個進程開始,另一個進入等待狀態。一旦孩子完成打印,它會向父母發出信號。現在,孩子的信號量值爲零,因此它在等待(child_sem)時等待孩子發信號的父母執行。下一次,父母發信號給孩子並執行。這在交替序列中繼續,是一個典型的同步問題。

+0

它看起來像這個代碼具有完全相同的行爲。我在'else'分支的開頭有一個'printf'語句,直到孩子的while循環運行一堆之後纔會顯示。聽起來問題可能是I/O而不是信號量。 –

1

好像控制流瞬間持續分叉過程,後來才恢復父進程

這是因爲流IO緩存上stdout輸出,直到

  • 的緩衝區已滿
  • fflush()被調用stdout
  • 換行符(\n)遇到

在你的程序中,每個進程將發送其內容stdout外觀運行很長一段時間,那麼另外一個進程的之前填寫的緩衝區。用\n終止printf語句的格式字符串,您會看到第一個程序中的行爲更像您期望的那樣。

我不知道爲什麼你的信號燈不工作 - 我對系統V信號燈不是很瞭解,但它似乎對我來說是一個紅旗,你在分叉後得到信號燈。有了更常見的POSIX信號量,信號量必須在內存中,兩個進程都能看到,否則就是兩個信號量。

無論如何,假設你的get_semaphore()函數做正確的事情來共享信號量,仍然存在一個問題,因爲不能保證當一個進程發出信號量的信號時,另一個進程會很快啓動以便抓住信號量再次在第一個過程循環並抓取它自己之前。

您需要兩個信號燈,一個用於父級,一個用於子級。在印刷之前,每個過程都應該等待自己的信號量。打印之後,每個進程應該發出另一個信號量的信號。另外,一個信號應該初始化爲1,另一個應該初始化爲0。

+0

對不起,我對這個人爲的例子有點sl in不安,實際上我在獲得信號前用換行符分叉和打印。更新了問題。 –

+0

試圖將一個進程打印到標準輸出,另一個打印到標準錯誤,但似乎子進程仍然在父進程恢復之前運行很長時間。 –