C-在另一个过程中访问共享内存缓冲区



我正在尝试使用静音和共享缓冲区来解决生产者消费者问题,但是在我的共享缓冲液结构(特别是char数组(中访问值时遇到困难。当我在一个终端中调用producer.c文件并打印值(输入是字母的txt文件(时使用

printf("%c", newBuff->bytes[newBuff->rear]); 

chars确实看起来很正常,但是当我在消费者中做同样的事情时,但是使用

printf("%c", newBuff->bytes[newBuff->front]);

值出现空白。newbuff->前值为零,因此应打印字母a。当我在消费者中访问结构中的其他值。共享内存创建以及附件也可以正常工作,因此我相信问题是我不是在阵列中正确存储char值,或者我试图错误地访问它们。在下面的代码中,我将printf放置在生产者的循环中,然后在消费者的循环外部,因此我知道在消费者开始提取数据之前存在价值。

消费者.c

typedef struct buffer{
    pthread_mutex_t lock;
    pthread_cond_t shout;
    int front;
    int rear;
    int count;
    int endOfFile;
    char bytes[1024];
} buffer;

int main(int argc, char const *argv[]) {
    int i=0;
    FILE *file = fopen(argv[1], "w");
    if (argc != 2){
        printf("You must enter in a file namen");
    }
    int shmid, swapCount=0;
    char swapBytes[] = "";
    char path[] = "~";
    key_t key = ftok(path, 7);
    buffer* newBuff;
    if ((shmid = shmget(key, SIZE, 0666 | IPC_CREAT | IPC_EXCL)) != -1) {
        newBuff = (buffer*) shmat(shmid, 0, 0);
        printf("successful creationn");
        newBuff->front = 0;
        newBuff->count = 0;
        newBuff->endOfFile = 0;
        pthread_mutexattr_t attr;
        pthread_condattr_t condAttr;
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
        pthread_mutex_init(&newBuff->lock, &attr);
        pthread_condattr_init(&condAttr);
        pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED);
        pthread_cond_init(&newBuff->shout, &condAttr);
    } //shared memory creation
    else if ((shmid = shmget(key, 0, 0)) != -1){
        printf("%dn", shmid);
        printf("successful attachmentn" );
        newBuff = (buffer*) shmat(shmid, 0, 0);
        printf("%cn", newBuff->count);
    }
    else{
        printf("oopsn");
        exit(0);
    }
    pthread_mutex_lock(&newBuff->lock);
    printf("%cn", newBuff->bytes[newBuff->front]);
    while (newBuff->endOfFile != 1)
    {
        while (newBuff->count == 0){
            pthread_cond_signal(&newBuff->shout);
            pthread_cond_wait(&newBuff->shout, &newBuff->lock);
        }
        newBuff->front = ((newBuff->front + 1)%SIZE);
        newBuff->count--;
    }
    pthread_mutex_unlock(&newBuff->lock);
    shmdt(&newBuff);
    //pthread_mutexattr_destroy(&attr);
    //pthread_condattr_destroy(&condAttr);*/
    return 0;
}

producer.c

typedef struct buffer{
    pthread_mutex_t lock;
    pthread_cond_t shout;
    int front;
    int rear;
    int count;
    int endOfFile;
    char bytes[1024];
} buffer;

int main(int argc, char const *argv[]) {
    FILE *file = fopen(argv[1], "r");
    if (argc != 2){
        printf("You must enter in a file dumbassn");
    }
    int shmid;
    char path[] = "~";
    key_t key = ftok(path, 7);
    buffer* newBuff;
    printf("dfasdfasdfn");
    if ((shmid = shmget(key, SIZE, 0666 | IPC_CREAT | IPC_EXCL)) != -1) {
        newBuff = (buffer*) shmat(shmid, 0, 0);
        printf("successful creationn");

        newBuff->front = 0;
        newBuff->count = 0;
        newBuff->endOfFile=0;
        pthread_mutexattr_t attr;
        pthread_condattr_t condAttr;
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
        pthread_mutex_init(&newBuff->lock, &attr);
        pthread_condattr_init(&condAttr);
        pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED);
        pthread_cond_init(&newBuff->shout, &condAttr);
    } //shared memory creation
    else if ((shmid = shmget(key, 0, 0)) != -1){
        printf("successful attachmentn" );
        newBuff = (buffer*) shmat(shmid, 0, 0);
    }
    else{
        printf("oopsn");
        exit(0);
    }
    printf("%dn", shmid);
    pthread_mutex_lock(&newBuff->lock);
    while (fscanf(file, "%c", &newBuff->bytes[newBuff->rear]) != EOF) //read in file
    {
        printf("%cn", newBuff->bytes[newBuff->rear]);
        while (newBuff->count >= SIZE){ //buffer is full
            //("%cn", newBuff->bytes[newBuff->rear]);
            pthread_cond_signal(&newBuff->shout);
            pthread_cond_wait(&newBuff->shout, &newBuff->lock);
        }
        //printf("%cn", newBuff->bytes[newBuff->rear]);
        newBuff->rear = ((newBuff->front + 1)%SIZE);
        newBuff->count++;
    }
    newBuff->endOfFile = 1;
    pthread_cond_signal(&newBuff->shout);
    pthread_mutex_unlock(&newBuff->lock);
    shmdt(&newBuff);
    //pthread_mutexattr_destroy(&attr);
    //pthread_condattr_destroy(&condAttr);
    return 0;
}

您的代码有几个困难,其中一些已经在评论中解决:

  • ftok()需要传递给它的路径以指定现有文件,但是您通过的路径却没有。

  • 您要求的共享存储器要比实际需要的要少:只有缓冲区内容的大小,而不是整个struct buffer。因为实际分配的共享内存数量将被舍入页面大小的倍数,所以这可能最终可以,但是您应该确保可以通过请求实际需要的金额来确保。

  • 系统v共享内存段具有内核持久性,因此创建后,它们将继续存在,直到明确删除或重新启动系统为止。您永远不会删除您的。您还只有在首次创建它时才初始化其内容。因此,除非您在运行之间手动删除它,否则您将使用旧数据(例如,在第二个且随后的运行中(使用旧数据。我建议将消费者计划删除。

  • 消费者仅在缓冲区中打印一个数据字节,并且在验证是否有任何阅读之前确实如此

  • 在向缓冲区添加字节后,生产者不会更新可用的字节数,直到充其量,这是浪费的,因为消费者在下次(如果有(醒来之前不会看到计数的变化。

  • 生产者基于当前 front 值,而不是基于当前的rear值,生产商不正确地更新缓冲区的rear索引。因此,数据将不会写入缓冲区阵列中的正确位置。

  • 一旦生产者设置了内向标志,消费者就会忽略除剩余的未读字节之一外的所有内容。

  • 如果生产商完成count零,则消费者将死亡。

我发现您的程序的修改版本成功,成功地通过共享内存来解决所有这些问题。

更新:

另外,

  • 消费者和/或生产者初始化静音和条件变量的方式本身并不安全。无论哪个过程都可以尝试shmget()秒(或第三或...(在初始化它们之前访问这些对象。更一般而言,一旦附加了共享内存段,就不会有固有的内存障碍涉及写作。为了解决这些问题,SYSV共享内存的自然伴侣是SYSV信号量。

最新更新