用于同步的全局信号量 - 计数器
global semaphores for synchronisation - counter
下面我在两个不同的进程中增加一个计数器 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, 0, 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
下面我在两个不同的进程中增加一个计数器 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, 0, 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