繁体   English   中英

共享内存不适用于结构,但适用于char *

[英]Shared memory doesn't work for a struct but works for a char*

这个错误对我来说花费了太多时间,我根本无法找出问题所在。

使用为char *创建的共享内存可以很好地工作,但是当我尝试将其用于创建的结构时,共享内存就无法正常工作。

语言是C。

目标

目标是创建一个将数据发送到第二个线程(由第一个线程创建)的线程。 数据保存在名为CircularQueue的结构中,必须使用共享内存进行传递。

同样,第一个线程一定不能等待第二个线程,它可以在第二个线程收到作为参数发送的共享内存的名称时结束。

CircularQueue

就我个人而言,我不认为问题出在这里,因为它可以很好地工作(至少直到现在我开始使用共享内存)。

CircularQueue是一种限制数据量的结构,它使用信号量和互斥量来做到这一点。 如果队列已满,则信号量使生产者等待,如果队列为空,则使使用者等待。 它使用互斥锁,因此一次只能写入1个。

问题

如果我将“ CircularQueue *”更改为“ char *”,将sizeof(CircularQueue)更改为sizeof(char)* NUMBER_OF_CHARS并在第一个线程上写入,则可以在第二个线程上读取它。 但事实并非如此。

主文件

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/types.h>
#include "CircularQueue.h"

typedef struct {
    char *v;
    sem_t sem;
} sharedMemoryName;

void * readThread(void * arg)
{
    // This first 3 lines is to get the name of the shared memory from the argument
    sharedMemoryName shm_name = *(sharedMemoryName *)arg;
    sem_post(&((*(sharedMemoryName *)arg).sem));
    printf("shm_name_2:%s:\n",shm_name.v);

    // This 2 lines open the shared memory
    int shmfd = shm_open(shm_name.v,O_RDWR,0600);
    if (shmfd<0) { perror("READER failure in shm_open()"); exit(1); }

    // This 2 lines attach the region of the virtual memory to the pointer
    CircularQueue *q = (CircularQueue *) mmap(0,sizeof(CircularQueue),PROT_READ|PROT_WRITE,MAP_SHARED,shmfd,0); //attach this region to virtual memory
    if (q == MAP_FAILED) { perror("READER failure in mmap()"); exit(2); }

    queue_print(q);   // Prints all the data of the CircularQueue (For Debug purposes)

    // Closes the virtual memory
    if (munmap(q,sizeof(CircularQueue)) < 0) { perror("READER failure in munmap()"); exit(4); } //unmap shared memory region
    if (shm_unlink(shm_name.v) < 0) { perror("READER failure in shm_unlink()"); exit(6); }

    return NULL;
}

void * writeThread(void * arg)
{
    // This first 4 lines is just for the name of the shared memory
    sharedMemoryName shm_name;
    snprintf(shm_name.v, sizeof shm_name.v, "%s%d", "/shm", 100);
    printf("shm_name_1:%s:\n",shm_name.v);
    sem_init(&(shm_name.sem), 0, 0);

    // This 3 lines create the shared memory
    int shmfd = shm_open(shm_name.v,O_CREAT|O_RDWR,0600);
    if (shmfd<0) { perror("WRITER failure in shm_open()"); exit(1); }
    if (ftruncate(shmfd,sizeof(CircularQueue)) < 0) { perror("WRITER failure in ftruncate()"); exit(2); }

    // This 2 lines attach the region of the virtual memory to the pointer
    CircularQueue *q = (CircularQueue *) mmap(0,sizeof(CircularQueue),PROT_READ|PROT_WRITE,MAP_SHARED,shmfd,0); //attach this region to virtual memory
    if (q == MAP_FAILED) { perror("WRITER failure in mmap()"); exit(3); }

    queue_init(&q,4);   // Initializes the CircularQueue
    queue_put(q,1,2);   // Puts the value 1 on the CircularQueue
    queue_print(q);     // Prints all the data of the CircularQueue (For Debug purposes)

    // Creates the next thread
    pthread_t nt;
    pthread_create(&nt, NULL, readThread, &shm_name);

    // Waits for the second thread (Reader) to read the argument, so it can end
    sem_wait(&(shm_name.sem));
    return NULL;
}

int main() {
    setbuf(stdout, NULL); // This is to avoid buffering in printf, therefore it prints immediatly
    pthread_t nt;
    pthread_create(&nt, NULL, writeThread, NULL);
    pthread_exit(NULL);
}

CircularQueue文件

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
typedef unsigned long QueueElem;
typedef struct
{
    QueueElem *v;       // pointer to the queue buffer
    unsigned int capacity;  // queue capacity
    unsigned int first; // head of the queue
    unsigned int last;  // tail of the queue
    sem_t empty;        // semaphores and mutex for implementing the
    sem_t full;     // producer-consumer paradigm
    pthread_mutex_t mutex;
} CircularQueue;
void queue_init(CircularQueue **q, unsigned int capacity)
{
    *q = (CircularQueue *) malloc(sizeof(CircularQueue));
    sem_init(&((*q)->empty), 0, capacity);
    sem_init(&((*q)->full), 0, 0);
    pthread_mutex_init(&((*q)->mutex), NULL);
    (*q)->v = (QueueElem *) malloc(capacity * sizeof(QueueElem));
    (*q)->capacity = capacity;
    (*q)->first = 0;
    (*q)->last = -1;
}
void queue_print(CircularQueue *q)
{
    int fullValue;
    sem_getvalue(&(q->full),&fullValue);
    if (fullValue!=0) {
        int i, emptyValue;
        if (q->first <= q->last) {
            for (i=q->first;i <= q->last;i++)
                printf("|%d:%d",i,(int)q->v[i]);
        } else {
            for (i=q->first;i < q->capacity;i++)
                printf("|%d:%d",i,(int)q->v[i]);
            for (i=0;i <= q->last;i++)
                printf("|%d:%d",i,(int)q->v[i]);
        }

        sem_getvalue(&(q->empty),&emptyValue);
        if (emptyValue==0)
            printf(" [FULL]");
    }
    else {
        printf("[EMPTY]");
    }

    printf("\n");
}
void queue_put(CircularQueue *q, QueueElem value, int n)
{
    sem_wait(&(q->empty));
    pthread_mutex_lock(&(q->mutex));
    q->last++;
    if ((q->last) >= (q->capacity))
        q->last = 0;
    q->v[q->last] = value;
    sem_post(&(q->full));
        printf("[%d]",n); queue_print(q);   // FOR DEBUG
    pthread_mutex_unlock(&(q->mutex));
}
QueueElem queue_get(CircularQueue *q, int n)
{
    QueueElem elem;
    sem_wait(&(q->full));
    pthread_mutex_lock(&(q->mutex));
    elem = q->v[q->first];
    q->first++;
    if ((q->first) >= (q->capacity))
        q->first = 0;
    sem_post(&(q->empty));
        printf("[%d]",n); printf("(GET:%d)",(int)elem); // FOR DEBUG
        queue_print(q);                 // FOR DEBUG
    pthread_mutex_unlock(&(q->mutex));
    return elem;
}
void queue_destroy(CircularQueue *q)
{
    free(q->v);
    pthread_mutex_destroy(&(q->mutex));
    sem_destroy(&(q->full));
    sem_destroy(&(q->empty));
    free(q);
}

控制台输出(printf)

shm_name_1:/shm100:
[2]|0:1               // This is printed by the queue_put(), when the first thread puts "1" in the queue (The 2, which is the 3rd argument of the function, is just for debug, this way I can see who wrote)
|0:1                  // This is printed by the first thread using queue_print()
shm_name_2:/shm100:   // The shared memory name is successfully passed
[EMPTY]               // This is printed by the second thread using queue_print()

感谢您的时间。

queue_init()您正在做

*q = (CircularQueue *) malloc(sizeof(CircularQueue));

这将覆盖您通过mmap()在写入器线程中检索到的共享内存地址。

所以q点,新malloc版内存而不是共享内存。

不要以为队列应该使用malloc()

另外,您应该将共享内存用于(*q)->v而不是分配为

 (*q)->v = (QueueElem *) malloc(capacity * sizeof(QueueElem));

如果您使用malloc()并在多个进程中使用共享内存,则(*q)->v在其他进程中将无效,并且可能会崩溃。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM