我在多进程程序之间共享一个计数器变量,其中使用fork()调用创建进程。我正在使用以下代码创建存储计数器的共享内存,并且可以通过每个进程访问和递增。
这是主要主线程
中的线程创建机制void createSHM()
{
int key = SHMKEY;
int *shm;
if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
perror("shmget");
exit(1);
}
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
*shm=0
}
这是在每个分叉进程中调用的函数,用于获取计数器的值,并将其递增。
int attachSHMandIncrement()
{
int key = SHMKEY;
int *shm;
if ((shmid = shmget(key, SHMSZ, 0666)) < 0) {
perror("shmget");
exit(1);
}
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
*shm++;
return *shm;
}
我不确定这个实现是否是免费的?任何人都可以评论它是否,如果没有,可以举例说明如何让这种情况免费参加比赛?
鉴于这些是分叉进程并且将在fork时继承内存。有什么我应该记住的吗?我之前在完全独立的流程中完成了这个,但在这里我可能必须在分叉流程中完成。
答案 0 :(得分:2)
由于你没有任何互斥锁,所以没有什么可以阻止两个进程同时尝试递增计数器,并且因为int
的增量通常不是原子的,所以这是一个直接竞争条件。除了增量竞赛之外,例程会递增,然后读取值,这也不是原子的,因此可以进行比赛。
为了避免比赛,你需要某种互斥。您可以使用信号量,或者您可以在共享内存中使用pthread互斥(如果您有可用的pthread)。或者,您可以使用文件锁,或者您可以编写自己的原子程序集例程并调用它们。如果您使用的是C11,您甚至可以使用stdatomic.h
中的内容。很多可能的选择。
修改强>
您可以围绕赛车操作包装互斥锁,以避免增量功能结束时的竞争条件:
struct sembuf sem_ops = { 0, -1, SEM_UNDO };
semop(semid, &sem_ops, 1);
*shm++;
rv = *shm;
sem_ops.sem_op = 1;
semop(semid, &sem_ops, 1);
return rv;
}
通常,您只需在每个进程中附加共享内存一次(并在一个进程中创建一次),然后只使用它,而无需重复附加和分离它。同样,您将创建并初始化互斥锁一次,然后使用它们。
答案 1 :(得分:0)
我在网上找到了一个适合我的解决方案。我在这里发帖,因为我想要一个示例代码作为答案。我希望这有助于其他人。
这是使用进程之间共享的mmapped区域,并使用互斥锁来确保没有竞争条件。
#include "unpipc.h"
#define SEM_NAME "mysem"
int main(int argc, char **argv)
{
int fd, i, nloop, zero = 0; 7 int *ptr;
sem_t *mutex;
if (argc != 3)
err_quit("usage: incr2 <#loops>");
nloop=atoi(argv[2]);
/* open file, initialize to 0, map into memory */
fd = Open(argv[1], O_RDWR | O_CREAT, FILE_MODE);
write(fd,&zero,sizeof(int));
ptr = Mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
/* create, initialize, and unlink semaphore */
mutex = Sem_open(Px_ipc_name(SEM_NAME), O_CREAT | O_EXCL, FILE_MODE, 1);
sem_unlink(Px_ipc_name(SEM_NAME));
setbuf(stdout, NULL); /* stdout is unbuffered */
if (Fork() == 0) { /* child */
for (i = 0; i < nloop; i++) {
sem_wait(mutex);
printf("child:%d\n",(*ptr)++);
sem_post(mutex);
}
exit(0);
}
/*parent*/
for (i = 0; i < nloop; i++) {
sem_wait(mutex);
printf("parent:%d\n",(*ptr)++);
sem_post(mutex);
}
exit(0);
}