我正在攻击单一的任务,并且遇到了我的代码的问题,该代码应该产生2个进程,其中第二个进程在执行之前等待1st完成。这就是我到目前为止所做的:
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);
现在,我知道在“现实世界”中,这真的很愚蠢。如果我的'消费者'在我的'制作人'完成之前什么都不做,那么你可能也没有这样的2个过程,但是这个任务试图说明一个竞争条件,所以为什么我们被特别告知这样做。
所以,我的问题是消费者流程不是在等待生产者。我假设由于信号量在生产者(sem_wait(&mutex);
)中被删除,因此在生产者中调用sem_post(&mutex);
之前,消费者无法使用它。
此外,据我所知,行wait(NULL);
并未等待两个流程完成。
我是否严重误解了某些事情?
答案 0 :(得分:10)
您应该对信号量调用进行错误检查。如果perror()
,sem_wait()
或sem_init()
返回非零,请使用sem_post()
来显示错误。
其次,你创造了比你想象的更多的流程。您的第一个fork()
会导致父级(producer
非零)和子级(producer
为零)。 两个进程然后执行第二个fork()
,因此您现在有四个进程。
第三,必须在进程之间共享sem_t
变量,因此必须将其存储在共享内存区域中。实现此目标的最简单方法是mmap()
:
sem_t *sem = mmap(NULL, sizeof *sem, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
(在sem_init()
和第一个fork()
之前执行。
第四,它没有定义哪个进程会先运行,所以你不能依赖于在消费者之前调用sem_wait()
的生产者线程。相反,使用sem_init()
将信号量初始化为零,并在消费者中仅 调用sem_wait()
- 这将阻止消费者。生产者执行,并在完成后调用sem_post()
,这允许消费者继续。
sem_init()
调用应将pshared
指定为非零,将value
指定为0,因此它应如下所示:
if (sem_init(sem, 1, 0) != 0) {
perror("sem_init");
exit(1);
}
第五,wait(NULL)
仅等待单个子进程退出。调用它两次等待两个子进程。
答案 1 :(得分:4)
仅仅因为你fork
生产者线程首先并不意味着操作系统会安排它先运行 - 消费者很可能实际运行并首先获得锁定。
另外,你应该检查sem_wait
的返回值 - 它可以在不保持信号量的情况下从它返回。
很可能(正如有几个人在评论中指出的那样)信号量可能无法在fork
个过程中起作用
编辑 - 如果在初始化posix信号量 跨进程工作时将{0}传递给sem_init(sem_t *sem, int pshared, unsigned value)
的参数2
编辑 - 请参阅here以获得比我能给出的更好的解释,完整的源代码几乎完全符合您的要求
答案 2 :(得分:1)
您是否在问题中提供了完整的代码?
如果是这样,您就缺少信号量初始化。在使用信号量之前,您必须先调用sem_init
或sem_open
。
阅读here。
编辑您在pshared
来电中指定sem_init
= 0。这使信号量进程本地化(即它只能用于同步一个进程的线程)。 fork
创建了一个子进程,因此信号量没有做任何有用的事情。
如果pshared的值为0,那么 信号量是在。之间共享的 一个过程的线程。如果是pshared 非零,然后共享信号量 进程之间。
(引用来自上面的链接)
答案 3 :(得分:0)
首先,我认为互斥体不会与进程一起使用。原因是分叉进程实际上并不共享内存。他们将能够读取与fork之前相同的内存,但只要其中一个内存写入内存,新进程就会收到自己的副本。
其次,您可能必须初始化互斥锁,否则可能未定义它们的使用。