共享内存和 POSIX 信号量

Posted

技术标签:

【中文标题】共享内存和 POSIX 信号量【英文标题】:Shared memory and POSIX semaphores 【发布时间】:2015-05-08 10:04:19 【问题描述】:

我用 C 编写了简单的消费者-生产者程序。当我有 1 个生产者和 1 个消费者时,它运行良好。但是当我增加消费者数量时,它的行为很奇怪。

    我启动生产者进程 制片人正在制作 我启动消费者进程 消费者在消费,生产者在生产 我启动 2 号消费者进程 消费者进程 no2 永远不会获得元素 当我启动消费者 no3、no4... 等等时,也会发生同样的情况

第二个问题:

    生产者生产了最多的元素 消费者消费所有元素,但生产者不再继续生产

我不知道为什么会这样。

代码:

制作人:

#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <fcntl.h>
#include "common.h"

int memoryID;
struct wrapper *memory;
int rc;

void atexit_function() 
    rc = shmctl(memoryID, IPC_RMID, NULL);
    rc = shmdt(memory);
    sem_destroy(&memory->pmutex);
    sem_destroy(&memory->cmutex);
    sem_destroy(&memory->empty);
    sem_destroy(&memory->full);


int main(int argc, char **argv) 
    atexit(atexit_function);
    //creating key for shared memory
    srand(time(NULL));
    key_t sharedMemoryKey = ftok(".", MEMORY_KEY);
    if (sharedMemoryKey == -1) 
        perror("ftok():");
        exit(1);
    

    memoryID = shmget(sharedMemoryKey, sizeof(struct wrapper), IPC_CREAT | 0600);
    if (memoryID == -1) 
        perror("shmget():");
        exit(1);
    

    memory = shmat(memoryID, NULL, 0);
    if (memory == (void *) -1) 
        perror("shmat():");
        exit(1);
    

    //initialization

    printf("Initializtaion !\n");
    memset(&memory->array, 0, sizeof(memory->array));
    sem_init(&memory->pmutex, 0, 1);
    sem_init(&memory->cmutex, 0, 1);
    sem_init(&memory->empty, 0, SIZE_OF_ARRAY);
    sem_init(&memory->full, 0, 0);
    memory->n = -1;

    if (memoryID == -1) 
        perror("shmget(): ");
        exit(1);
    


    while(1)
    
        int r = rand();
        sem_wait(&memory->empty);
        sem_wait(&memory->pmutex);
        memory->n++;
        (memory->array)[memory->n]=r;
        printf("Adding task\t Value:%d\tNumber of tasks waiting:%d \n",r,memory->n);
        usleep(10000);
        sem_post(&memory->pmutex);
        sem_post(&memory->full);
    


消费者:

#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
#include <sys/shm.h>

int memoryID;
struct wrapper *memory;
int check_prime(int a);
int main(int argc, char **argv) 
    srand(time(NULL));
    key_t sharedMemoryKey = ftok(".",MEMORY_KEY);
    if(sharedMemoryKey==-1)
    
        perror("ftok():");
        exit(1);
    
    memoryID=shmget(sharedMemoryKey,sizeof(struct wrapper),0);

    if(memoryID==-1)
    
        perror("shmget(): ");
        exit(1);
    

    memory = shmat(memoryID,NULL,0);
    if(memory== (void*)-1)
    
        perror("shmat():");
        exit(1);
    

    while(1)
    
        sem_wait(&memory->full);
        sem_wait(&memory->cmutex);

        int n = memory->n;
        int temp = (memory->array)[n];
        printf("Removed item: %d\tPrime:%d\tNumer of tasks left:%d\n",
            temp, check_prime(temp),n);
        memory->n--;
        usleep(10000);

        sem_post(&memory->cmutex);
        sem_post(&memory->empty);
    


common.h:

#define MEMORY_KEY 12
#define SIZE_OF_ARRAY 10
struct wrapper

    int array[SIZE_OF_ARRAY];
    sem_t empty;
    sem_t pmutex;
    sem_t cmutex;
    sem_t full;
    int n;
;

【问题讨论】:

我认为您必须为其他流程留出时间来获取 sem。例如。 sem 发布后睡一会儿。 不幸的是它没有帮助 发布的代码似乎过于复杂。似乎没有/零需要任何信号量。数据需要互斥体、计数器和数组。当没有可处理的对象/int 时,消费者需要睡一会儿。当数组已满时,生产者需要休眠一会儿。我还建议,为避免未及时处理旧数据,将数组视为带有头尾指针的循环列表 【参考方案1】:

问题解决了。 我正在设置int sem_init(sem_t *sem, int pshared, unsigned int value); 我将 pshared 值设置为 0 但是:

   The pshared argument indicates whether this semaphore  is  to  be  shared  between  the
   threads of a process, or between processes.

  If  pshared  has  the  value  0,  then the semaphore is shared between the threads of a
   process, and should be located at some address that is visible to all threads (e.g.,  a
   global variable, or a variable allocated dynamically on the heap).

  If  pshared  is  nonzero, then the semaphore is shared between processes, and should be
   located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2)).  (Since
   a  child  created  by fork(2) inherits its parent's memory mappings, it can also access
   the semaphore.)  Any process that can access the shared memory region  can  operate  on
   the semaphore using sem_post(3), sem_wait(3), etc.

【讨论】:

以上是关于共享内存和 POSIX 信号量的主要内容,如果未能解决你的问题,请参考以下文章

如何在 c 中使用 posix 命名信号量和 Linux 上两个进程之间的共享内存?

信号量

RE:Posix 和 System V IPC

Linux Program信号量共享内存和消息队列

共享内存原理

信号量学习 & 共享内存同步