2017-04-07 148 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

试图将一个进程打印到标准输出,另一个打印到标准错误,但似乎子进程仍然在父进程恢复之前运行很长时间。 –