[英]Shared memory doesn't work for a struct but works for a char*
这个错误对我来说花费了太多时间,我根本无法找出问题所在。
使用为char *创建的共享内存可以很好地工作,但是当我尝试将其用于创建的结构时,共享内存就无法正常工作。
语言是C。
目标是创建一个将数据发送到第二个线程(由第一个线程创建)的线程。 数据保存在名为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);
}
#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);
}
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.