[英]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.