我正在尝试使用静音和共享缓冲区来解决生产者消费者问题,但是在我的共享缓冲液结构(特别是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信号量。