簡體   English   中英

C中的進程同步不是第一次執行

[英]Process Synchronisation in C does not execute the first time

所以我在C中的進程同步程序遇到了這個問題。

我應該編寫一個使用fork()的代碼,它將產生如下內容:

PARENT
PARENT
CHILD
PARENT
CHILD
PARENT

使用我在這里找到的代碼,我能夠使它工作,但是由於某些原因,出現在屏幕上的第一個結果是混亂的,而其他所有的工作都很好。

要編譯,請輸入: gcc test.c display.c -o test -pthread

無論如何,這是我正在測試的代碼(我重復:這不是我的代碼):

#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

int main(void)
{
  int i;
  /* place semaphore in shared memory */
  sem_t *sema = mmap(NULL, sizeof(sema), PROT_READ |PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1, 0);
  /* create/initialize semaphore */
  if ( sem_init(sema, 1, 0) < 0)
  {
    perror("sem_init");
    exit(EXIT_FAILURE);
  }
  int nloop=10;
  int pid = fork();
  if (pid == 0)
  { 
    for (i = 0; i < nloop; i++)
    {
      // child unlocks semaphore
      display("CHILD\n");
      if (sem_post(sema) < 0)
          perror("sem_post");
      sleep(1);
    }
    if (munmap(sema, sizeof(sema)) < 0)
    {
      perror("munmap");
      exit(EXIT_FAILURE);
    }
      exit(EXIT_SUCCESS);
  }
  else
  {
    for (i = 0; i < nloop; i++)
    { // parent starts waiting
      display("PARENT\n");
      if (sem_wait(sema) < 0) 
        perror("sem_wait");
    // parent finished waiting
    }
    if (sem_destroy(sema) < 0)
    {
      perror("sem_destroy failed");
      exit(EXIT_FAILURE);
    }
    if (munmap(sema, sizeof(sema)) < 0)
    {
      perror("munmap failed");
      exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
  }
}

這是輸出:

PACREHNT
ILD
PARENT
CHILD
PARENT
CHILD
PARENT
CHILD
PARENT
CHILD
PARENT
CHILD
PARENT
CHILD
PARENT
CHILD
PARENT
CHILD
PARENT
CHILD

為什么會在一開始就發生這種情況?

您不能編寫使用單個信號量在父進程和子進程之間切換的程序(而無需訴諸某種形式的忙於標志或其他東西的等待),因為兩個進程都將爭相獲取信號量。 無法預測哪個進程將首先獲取它。 您的代碼(第一次迭代除外)似乎可以按預期工作,因為孩子睡眠時間很長,但是從技術上講,這仍然是一個競爭條件,不能保證父母可以在獲取之前獲得機會。孩子醒來(盡管可能性很小)。

因此,您需要2個信號量:一個由孩子用來通知父母該輪到他了,另一個由父母用來通知孩子。 要選擇誰先開始,請將相應的信號量初始化為1(另一個初始化為0)。

另外,這是錯誤的:

sem_t *sema = mmap(NULL, sizeof(sema), PROT_READ |PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1, 0);

第二個參數應為sizeof(*sema)因為您要為信號對象而不是指針分配內存。

您可能永遠不會#include "display.h"

錯誤處理可以改善,但是對於這個玩具程序,我認為這沒什么大不了的。

這是一個使用2信號量方法的工作版本(它將父信號量初始化為1,因此父信號量將首先啟動):

#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

int main(void)
{
    int i;
    /* place semaphore in shared memory */
    sem_t *child_sem = mmap(NULL, sizeof(*child_sem), PROT_READ |PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1, 0);
    sem_t *parent_sem = mmap(NULL, sizeof(*parent_sem), PROT_READ |PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1, 0);

    /* create/initialize semaphore */
    if ( sem_init(child_sem, 1, 0) < 0)
    {
        perror("sem_init");
        exit(EXIT_FAILURE);
    }

    if (sem_init(parent_sem, 1, 1) < 0) {
        perror("sem_init");
        exit(EXIT_FAILURE);
    }

    int nloop=10;
    int pid = fork();
    if (pid == 0)
    {
        for (i = 0; i < nloop; i++)
        {
            if (sem_wait(child_sem) < 0)
                perror("sem_wait");
            display("CHILD\n");
            if (sem_post(parent_sem) < 0)
                perror("sem_post");
            sleep(1);
        }
    }
    else
    {
        for (i = 0; i < nloop; i++)
        { // parent starts waiting
            if (sem_wait(parent_sem) < 0) 
                perror("sem_wait");
            display("PARENT\n");
            if (sem_post(child_sem) < 0)
                perror("sem_post");
        }
    }
}

為了簡明起見,我刪除了munmap(2)sem_destroy(3)調用,並且由於它們已經退出,因此它們是不必要的。

請注意,兩個進程遵循相同的模式:等待它們的信號燈,開始工作,通知另一個進程的信號燈。 這是一個很好的機會,可以進行一些重構並將其全部移至一個函數,該函數接收要顯示的字符串,等待信號量以及隨后通知信號量。

您還應該習慣於-Wall進行編譯。

暫無
暫無

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

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