代码之家  ›  专栏  ›  技术社区  ›  Ash

为什么我的互斥在多进程C应用程序中不能正常工作?

  •  5
  • Ash  · 技术社区  · 14 年前

    我正在破解一个uni分配,我的代码遇到了一个问题,它应该产生2个进程,第二个进程在执行前等待第一个进程完成。这就是我目前为止所拥有的:

    sem_t mutex;
    int producer; int consumer;
    sem_init(&mutex, 0, 1);
    producer = fork();
    consumer = fork();
    
    if (producer == 0) {
        if (VERBOSE) printf("Running producer\n");
        /* down semaphore */
        sem_wait(&mutex);
        /* START CRITICAL REGION */
        get_files(N);
        /* END CRITICAL REGION */
        /* up semaphore */
        sem_post(&mutex);
        if (VERBOSE) printf("Ending producer\n");
        exit(0);
    }
    
    if (consumer == 0) {
        if (VERBOSE) printf("Running consumer\n");
        /* down semaphore */
        sem_wait(&mutex);
        /* START CRITICAL REGION */
        /* do stuff */
        /* END CRITICAL REGION */
        /* up semaphore */
        sem_post(&mutex);
        if (VERBOSE) printf("Ending consumer\n");
        exit(0);
    }
    /* parent waits for both to complete */
    wait(NULL);
    

    现在,我知道在“现实世界”中,这真的很愚蠢。如果我的“消费者”在我的“生产商”完成之前什么也不做,那么你也可能没有这样的两个过程,但是任务是试图说明一个竞争条件,所以我们被特别要求这样做的原因。

    所以,我的问题是,消费者过程并不等待生产者。我想既然信号灯是在生产商那里取下来的( sem_wait(&mutex); )那么,直到 sem_post(&mutex); 在生产商中调用。

    另外,据我所知,这条线 wait(NULL); 不等待两个进程都完成。

    我有没有严重误解什么?

    4 回复  |  直到 12 年前
        1
  •  4
  •   tobyodavies    14 年前

    只是因为你 fork 生产者线程优先并不意味着操作系统会安排它首先运行——很可能消费者实际运行并首先获得锁。

    另外,您应该检查 sem_wait -它可以在不保留信号量的情况下从中返回。

    也很有可能(正如一些人在评论中指出的那样),信号量可能根本无法跨越 ED过程

    编辑-如果将非零值传递给的参数2 sem_init(sem_t *sem, int pshared, unsigned value) 初始化POSIX信号灯时 跨流程工作

    编辑-参见 here 为了得到比我所能给出的更好的解释,用源代码来完成你想要的工作。

        2
  •  10
  •   caf    14 年前

    检查信号灯调用时应该出错。使用 perror() 显示错误,如果 sem_wait() , sem_init() sem_post() 返回非零。

    第二,你创造的过程比你想象的要多。你的第一个 fork() 产生一个父级 producer 非零)和一个孩子(带 生产者 零)。 两个 然后执行第二个进程 Frk() ,你现在有了 过程。

    三是 sem_t 变量必须在进程之间共享,因此必须存储在共享内存区域中。最简单的方法是 mmap() :

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

    (在 sem_初始化() 还有第一个 Frk() )

    第四,它没有定义哪个进程将首先运行,因此不能依赖于生产者线程调用 扫描电镜等待( 在消费者之前。相反,将信号量初始化为零 sem_初始化() 只有 呼叫 扫描电镜等待( 在消费者中-这将阻止消费者。生产者执行并调用 sem_post()后 完成后,用户可以继续。

    这个 sem_初始化() 调用应指定 pshared 非零和 value 为0,因此应该如下所示:

    if (sem_init(sem, 1, 0) != 0) {
        perror("sem_init");
        exit(1);
    }
    

    第五, wait(NULL) 只等待单个子进程退出。调用两次以等待两个子进程。

        3
  •  1
  •   atzz    14 年前

    您是否提供了问题的完整代码?

    如果是这样,则缺少信号量初始化。你也得打电话 sem_init sem_open 在使用信号灯之前。

    here .

    编辑 您正在指定 pshared =0在 扫描电镜初始化 打电话。这使信号量进程成为本地进程(即,它只能用于同步一个进程的线程)。 fork 创建子进程,因此信号量不做任何有用的事情。

    如果pshared的值为0,则 信号量在 进程的线程。如果pshared是 非零,则信号量共享 过程之间。

    (引用自以上链接)

        4
  •  0
  •   gablin    14 年前

    首先,我不认为互斥体可以与进程一起工作。原因是分叉的进程实际上不共享内存。它们将能够读取与fork之前相同的内存,但每当其中一个写入内存时,新进程将收到自己的副本。

    第二,您可能需要初始化互斥体,否则互斥体的用法可能未定义。