访问另一个进程中的共享内存缓冲区
Accessing a shared memory buffer in another process
我正在尝试使用互斥体和共享缓冲区来解决生产者消费者问题,但在访问我的共享缓冲区结构中的值时遇到问题,特别是 char 数组。当我在一个终端中调用 producer.c 文件并使用
打印值(输入是字母表的 txt 文件)时
printf("%c", newBuff->bytes[newBuff->rear]);
字符确实显示正常,但是当我在 consumer.c 中做同样的事情时,但
printf("%c", newBuff->bytes[newBuff->front]);
这些值显示为空白。 newBuff->front 的值为零,所以它应该打印字母 a。当我在 consumer.c 中访问我的结构中的其他值时,如 front、count 或 rear,它们是正确的。共享内存创建和附件也能正常工作,所以我认为问题是我没有在数组中正确存储 char 值,或者我试图错误地访问它们。在下面的代码中,我将 printf 放在 producer.c 的循环中,然后放在 consumer.c 的循环之外,所以我知道在消费者开始提取数据之前存在一个值。
Consumer.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 name\n");
}
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 creation\n");
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("%d\n", shmid);
printf("successful attachment\n" );
newBuff = (buffer*) shmat(shmid, 0, 0);
printf("%c\n", newBuff->count);
}
else{
printf("oops\n");
exit(0);
}
pthread_mutex_lock(&newBuff->lock);
printf("%c\n", 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 dumbass\n");
}
int shmid;
char path[] = "~";
key_t key = ftok(path, 7);
buffer* newBuff;
printf("dfasdfasdf\n");
if ((shmid = shmget(key, SIZE, 0666 | IPC_CREAT | IPC_EXCL)) != -1) {
newBuff = (buffer*) shmat(shmid, 0, 0);
printf("successful creation\n");
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 attachment\n" );
newBuff = (buffer*) shmat(shmid, 0, 0);
}
else{
printf("oops\n");
exit(0);
}
printf("%d\n", shmid);
pthread_mutex_lock(&newBuff->lock);
while (fscanf(file, "%c", &newBuff->bytes[newBuff->rear]) != EOF) //read in file
{
printf("%c\n", newBuff->bytes[newBuff->rear]);
while (newBuff->count >= SIZE){ //buffer is full
//("%c\n", newBuff->bytes[newBuff->rear]);
pthread_cond_signal(&newBuff->shout);
pthread_cond_wait(&newBuff->shout, &newBuff->lock);
}
//printf("%c\n", 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
。因为实际分配的共享内存量将四舍五入为页面大小的倍数,所以这可能最终没问题,但你应该确保通过请求数量来确定它会没问题你真的需要。
System V 共享内存段具有内核持久性,因此一旦创建,它们将继续存在,直到它们被显式删除或系统重新启动。你永远不会删除你的。您也只有在第一次创建它时才初始化它的内容。因此,除非您在运行之间手动删除它,否则您将在第二次和后续运行中使用旧数据——例如,设置了文件结束指示器。我建议让消费者安排移除它。
消费者只从缓冲区打印一个字节的数据,它在之前验证是否有任何内容可读。
向缓冲区添加一个字节后,生产者不会更新可用字节数,直到 向消费者发送信号后。 充其量,这是一种浪费,因为直到下次(如果有的话)它被唤醒时,消费者才会看到计数的变化。
生产者根据当前的front
值错误地更新了缓冲区的rear
索引而不是当前的 rear
值。因此,数据将不会写入缓冲区数组中的正确位置。
一旦生产者设置了 endOfFile 标志,消费者将忽略除一个剩余未读字节之外的所有字节。
如果生产者在完成时将 count
置零,消费者将死锁。
我发现您的程序的修改版本成功地解决了所有这些问题,并通过共享内存准确地传递数据。
更新:
此外,
- 消费者和/或生产者初始化互斥量和条件变量的方式本身并不安全。在第一个完成初始化之前,任何进程都可能尝试
shmget()
第二次(或第三次,或...)访问这些对象。更一般地说,一旦附加了一个共享内存段,写入它就没有固有的内存屏障。为了解决这些问题,SysV 共享内存的天然伴侣是 SysV 信号量。
我正在尝试使用互斥体和共享缓冲区来解决生产者消费者问题,但在访问我的共享缓冲区结构中的值时遇到问题,特别是 char 数组。当我在一个终端中调用 producer.c 文件并使用
打印值(输入是字母表的 txt 文件)时printf("%c", newBuff->bytes[newBuff->rear]);
字符确实显示正常,但是当我在 consumer.c 中做同样的事情时,但
printf("%c", newBuff->bytes[newBuff->front]);
这些值显示为空白。 newBuff->front 的值为零,所以它应该打印字母 a。当我在 consumer.c 中访问我的结构中的其他值时,如 front、count 或 rear,它们是正确的。共享内存创建和附件也能正常工作,所以我认为问题是我没有在数组中正确存储 char 值,或者我试图错误地访问它们。在下面的代码中,我将 printf 放在 producer.c 的循环中,然后放在 consumer.c 的循环之外,所以我知道在消费者开始提取数据之前存在一个值。
Consumer.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 name\n");
}
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 creation\n");
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("%d\n", shmid);
printf("successful attachment\n" );
newBuff = (buffer*) shmat(shmid, 0, 0);
printf("%c\n", newBuff->count);
}
else{
printf("oops\n");
exit(0);
}
pthread_mutex_lock(&newBuff->lock);
printf("%c\n", 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 dumbass\n");
}
int shmid;
char path[] = "~";
key_t key = ftok(path, 7);
buffer* newBuff;
printf("dfasdfasdf\n");
if ((shmid = shmget(key, SIZE, 0666 | IPC_CREAT | IPC_EXCL)) != -1) {
newBuff = (buffer*) shmat(shmid, 0, 0);
printf("successful creation\n");
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 attachment\n" );
newBuff = (buffer*) shmat(shmid, 0, 0);
}
else{
printf("oops\n");
exit(0);
}
printf("%d\n", shmid);
pthread_mutex_lock(&newBuff->lock);
while (fscanf(file, "%c", &newBuff->bytes[newBuff->rear]) != EOF) //read in file
{
printf("%c\n", newBuff->bytes[newBuff->rear]);
while (newBuff->count >= SIZE){ //buffer is full
//("%c\n", newBuff->bytes[newBuff->rear]);
pthread_cond_signal(&newBuff->shout);
pthread_cond_wait(&newBuff->shout, &newBuff->lock);
}
//printf("%c\n", 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
。因为实际分配的共享内存量将四舍五入为页面大小的倍数,所以这可能最终没问题,但你应该确保通过请求数量来确定它会没问题你真的需要。System V 共享内存段具有内核持久性,因此一旦创建,它们将继续存在,直到它们被显式删除或系统重新启动。你永远不会删除你的。您也只有在第一次创建它时才初始化它的内容。因此,除非您在运行之间手动删除它,否则您将在第二次和后续运行中使用旧数据——例如,设置了文件结束指示器。我建议让消费者安排移除它。
消费者只从缓冲区打印一个字节的数据,它在之前验证是否有任何内容可读。
向缓冲区添加一个字节后,生产者不会更新可用字节数,直到 向消费者发送信号后。 充其量,这是一种浪费,因为直到下次(如果有的话)它被唤醒时,消费者才会看到计数的变化。
生产者根据当前的
front
值错误地更新了缓冲区的rear
索引而不是当前的rear
值。因此,数据将不会写入缓冲区数组中的正确位置。一旦生产者设置了 endOfFile 标志,消费者将忽略除一个剩余未读字节之外的所有字节。
如果生产者在完成时将
count
置零,消费者将死锁。
我发现您的程序的修改版本成功地解决了所有这些问题,并通过共享内存准确地传递数据。
更新:
此外,
- 消费者和/或生产者初始化互斥量和条件变量的方式本身并不安全。在第一个完成初始化之前,任何进程都可能尝试
shmget()
第二次(或第三次,或...)访问这些对象。更一般地说,一旦附加了一个共享内存段,写入它就没有固有的内存屏障。为了解决这些问题,SysV 共享内存的天然伴侣是 SysV 信号量。