分叉 3 次,试图始终如一地输出在循环中递增的值

问题描述

目标是让输出从 1 开始并达到 150,目前只有 1 到 60,并且有多个重复。我想保持 main 不变,只使用信号量来处理 process() 函数。这是我对如何使用post和wait的解释。如果这是错误的,请告诉我。

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>
// //dev/shm/sem.X <- unlinks
sem_t *sem;
/*
    sem = sem_open("X",O_CREAT | O_EXCL,0777,N);
    sem_unlink("X");
    sem_getvalue(sem,&N);
    sem_post(sem);
*/
void process(){
    int ret;
    int N = 1;
    int a;
    sem = sem_open("X",1);
    sem_unlink("X");
    
    for(int i = 0; i< 50; i++){
        sem_wait(sem);
        FILE* infile = fopen ("infile.txt","r");
        fscanf (infile,"%d",&N); 
        fclose (infile);
        N++;
        printf("N: %d Process ID: %d \n",N,getpid());
        infile = fopen("infile.txt","w");
        fprintf(infile,N);
        fclose(infile);
        sem_post(sem);
    }
    
    exit(0);
}
int main(){
    
    FILE *fp = fopen("infile.txt","w");
    fprintf(fp,1);
    fclose(fp);
    
    int pid,pid1,pid2;
    pid = fork();
    if(pid == 0){
        //child1,Last
        printf("Starting Process C: \n");
        process();
    }
    else{
        pid1 = fork();
        if(pid1 == 0){
            //child2,Middle
            printf("Starting Process B: \n");
            process();
        }
        else{
            pid2 = fork();
            if(pid2 == 0){
                //child 3,First
                printf("Starting Process A: \n");
                process();
            }
            else{

            }
        }
        
    }
    //sem_close(&X);
}

解决方法

sem_open 中执行 process 后跟 sem_unlink 是不正确的。

每个进程将获得一个不同信号量,因此它们将协调。

sem_open 移至 main 并删除 sem_unlink。然后,所有进程将使用相同/正确的信号量。

请注意,主/主进程不执行 wait [并立即终止],因此子进程附加到 init 进程。更好的做法:while (wait(NULL) >= 0);main

的底部

我们需要在sem_close的底部做sem_unlink然后main


这是一些重构的代码。注释:

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

// //dev/shm/sem.X <- unlinks
sem_t *sem;

#if 0
sem = sem_open("X",O_CREAT | O_EXCL,0777,N);
sem_unlink("X");
sem_getvalue(sem,&N);
sem_post(sem);
#endif

void
process()
{
    int ret;
    int N = 1;
    int a;

// NOTE/BUG: by doing this here each process gets it's own semaphore so nothing
// will be coordinated
#if 0
    sem = sem_open("X",1);
    sem_unlink("X");
#endif

    for (int i = 0; i < 50; i++) {
        sem_wait(sem);
        FILE *infile = fopen("infile.txt","r");

        fscanf(infile,"%d",&N);
        fclose(infile);
        N++;
        printf("N: %d Process ID: %d \n",N,getpid());
        infile = fopen("infile.txt","w");
        fprintf(infile,N);
        fclose(infile);
        sem_post(sem);
    }

    exit(0);
}

int
main()
{

    FILE *fp = fopen("infile.txt","w");
    fprintf(fp,1);
    fclose(fp);

// NOTE/FIX: one semaphore for all processes
#if 1
    sem = sem_open("X",1);
    //sem_unlink("X");
#endif

    int pid,pid1,pid2;

    pid = fork();
    if (pid == 0) {
        // child1,Last
        printf("Starting Process C: \n");
        process();
    }
    else {
        pid1 = fork();
        if (pid1 == 0) {
            // child2,Middle
            printf("Starting Process B: \n");
            process();
        }
        else {
            pid2 = fork();
            if (pid2 == 0) {
                // child 3,First
                printf("Starting Process A: \n");
                process();
            }
            else {

            }
        }

    }
    // sem_close(&X);

// NOTE/FIX: wait for all subprocesses to finish
#if 1
    while (1) {
        pid = wait(NULL);
        if (pid < 0)
            break;
    }
#endif

// NOTE/FIX: we must close and unlink so that we can be invoked again
#if 1
    sem_close(sem);
    sem_unlink("X");
#endif

    return 0;
}

上述方法有效,但我会使用循环来启动三个进程,而不是嵌套的 if/else 语句。如果我们必须创建 1000 个进程,这个解决方案会更明显:

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

// //dev/shm/sem.X <- unlinks
sem_t *sem;

#if 0
sem = sem_open("X",1);
    //sem_unlink("X");
#endif

    pid_t pid;

    for (int count = 1;  count <= 3;  ++count) {
        pid = fork();
        if (pid == 0)
            process();
    }

// NOTE/FIX: wait for all subprocesses to finish
#if 1
    while (1) {
        pid = wait(NULL);
        if (pid < 0)
            break;
    }
#endif

// NOTE/FIX: we must close and unlink so that we can be invoked again
#if 1
    sem_close(sem);
    sem_unlink("X");
#endif

    return 0;
}