问题描述
以下,我在两个不同的过程中将计数器增加1000,并使用全局信号量进行同步。但是iCounter不给我2000吗?有人可以向我解释为什么吗?
#include <stdio.h>
#include <semaphore.h>
#include <stdlib.h>
#include <fcntl.h>
#define SEM_NAME "/sync"
#define NUMBER_OF_PROCESSES 2
int main ()
{
int iCounter = 0;
pid_t pid[NUMBER_OF_PROCESSES];
sem_t *sSem = sem_open (SEM_NAME,O_CREAT | O_EXCL,S_IRWXU | S_IRWXG | S_IRWXO,1);
int i,iStatus;
for (i = 0; i < NUMBER_OF_PROCESSES; i++)
{
pid[i] = fork ();
if (pid[i] < 0)
{
printf ("Could not create process\n");
exit (1);
}
else if (pid[i] == 0)
{
int i;
for (i = 0; i < 1000; i++)
{
sem_init(sSem,1);
sem_wait (sSem);
iCounter++;
sem_post (sSem);
}
exit (0);
}
}
for (i = 0; i < NUMBER_OF_PROCESSES; i++)
waitpid (pid[i],&iStatus,WUNTRACED);
printf ("Value of iCounter = %d\n",iCounter);
sem_close (sSem);
sem_unlink (SEM_NAME);
}
解决方法
您有两个大问题:
-
您没有正确使用命名信号量。
sem_init()
仅可用于匿名用户,每个信号量仅可使用一次,您可以在已初始化的信号上多次调用它。这是未定义的行为。 -
您创建的进程之间没有共享您的
iCounter
变量。
程序的以下重新制作是使用POSIX共享内存分配的(并进行了一些常规清理):
#include <errno.h>
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define SEM_NAME "/sync"
#define SHM_NAME "/counter"
#define NUMBER_OF_PROCESSES 2
int main() {
int *iCounter = MAP_FAILED;
pid_t pid[NUMBER_OF_PROCESSES];
int iStatus;
int ret = 0;
int memfd = -1;
sem_t *sSem = sem_open(SEM_NAME,O_CREAT | O_EXCL,S_IRUSR | S_IWUSR,1);
if (sSem == SEM_FAILED) {
perror("sem_open");
ret = 1;
goto cleanup;
}
memfd = shm_open(SHM_NAME,O_RDWR | O_CREAT | O_EXCL,S_IRUSR | S_IWUSR);
if (memfd < 0) {
perror("shm_open");
ret = 1;
goto cleanup;
}
if (ftruncate(memfd,sizeof *iCounter) < 0) {
perror("ftruncate");
ret = 1;
goto cleanup;
}
iCounter = mmap(NULL,sizeof *iCounter,PROT_READ | PROT_WRITE,MAP_SHARED,memfd,0);
if (iCounter == MAP_FAILED) {
perror("mmap");
ret = 1;
goto cleanup;
}
close(memfd);
*iCounter = 0;
for (int i = 0; i < NUMBER_OF_PROCESSES; i++) {
pid[i] = fork();
if (pid[i] < 0) {
fprintf(stderr,"Could not create process: %s\n",strerror(errno));
ret = 1;
goto cleanup;
} else if (pid[i] == 0) {
for (i = 0; i < 1000; i++) {
sem_wait(sSem);
(*iCounter)++;
sem_post(sSem);
}
sem_close(sSem);
return 0;
}
}
for (int i = 0; i < NUMBER_OF_PROCESSES; i++)
waitpid(pid[i],&iStatus,WUNTRACED);
printf("Value of iCounter = %d\n",*iCounter);
cleanup:
if (sSem != SEM_FAILED) {
sem_close(sSem);
sem_unlink(SEM_NAME);
}
if (memfd >= 0)
shm_unlink(SHM_NAME);
return ret;
}
示例:
$ gcc -g -O -Wall -Wextra example.c -lrt -lpthread
$ ./a.out
Value of iCounter = 2000