如何在共享内存分叉进程中使用互斥锁?

时间:2014-12-01 01:20:04

标签: c ipc mutex shared-memory

我在多进程程序之间共享一个计数器变量,其中使用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;
}
  1. 我不确定这个实现是否是免费的?任何人都可以评论它是否,如果没有,可以举例说明如何让这种情况免费参加比赛?

  2. 鉴于这些是分叉进程并且将在fork时继承内存。有什么我应该记住的吗?我之前在完全独立的流程中完成了这个,但在这里我可能必须在分叉流程中完成。

2 个答案:

答案 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  &lt;#loops&gt;");
     nloop=atoi(argv[2]); 
      /* open file, initialize to 0, map into memory */
      fd = Open(argv[1], O_RDWR | O_CREAT, FILE_MODE);
     write(fd,&amp;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 &lt; nloop; i++) {
         sem_wait(mutex);
         printf("child:%d\n",(*ptr)++); 
         sem_post(mutex);
     }
     exit(0);
     }
     /*parent*/ 
     for (i = 0; i &lt; nloop; i++) {
        sem_wait(mutex);
        printf("parent:%d\n",(*ptr)++); 
        sem_post(mutex);
     }
      exit(0);
     }