gpt4 book ai didi

C Ring Buffer 共享内存信号量 ReadPointer WritePointer Not Right

转载 作者:行者123 更新时间:2023-12-04 18:29:46 26 4
gpt4 key购买 nike

我想使用 Reader-Writer Synchronization Paradigm 构建一个文件复制器。
Writer 初始化这两个互斥锁。 FullMutex 表示有多少 Buffer 可供写入,而 FreeMutex 表示有多少 Buffer 可供读取。
当 Block 已满时,Writer 等待。
WritePointer 和 ReadPointer 正在使用 Ring Buffer。因此我使用了Mod Operation。
block 大小=M。
缓冲区大小=B。
有 N 个 Buffer。
所以,M=N*B。
文件大小=2M。
因此 BufferCount 实际上是在推进文件指针。
写入所有字节后,我发出 FileEnding=1。

编译命令是 -

g++ Writer.c -o Writer -lpthread -lrt
g++ Reader.c -o Reader -lpthread -lrt

并在 2 个不同的命令提示符中打开并发出命令-
./Writer
./Reader

现在我不知道为什么 ReadPointer 和 WritePointer 会这样来?

这是Writer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>

int main(void){
char FileName[128]="aaa.txt";
struct MemData{
sem_t FullMutex;
sem_t FreeMutex;
int ReadPointer;
int WritePointer;
int FileEnding;
char Data[512000];//MEMORY BLOCK SIZE: 500 KB
};
int SD;
struct MemData *M;
int NumberOfBuffers=10;
//int BufferSize=51200;//FILE BUFFER SIZE 50 KB
int BufferSize=2;//EXPERIMENATION
unsigned char Buf[BufferSize];
int BufferCount=0;

SD= shm_open("/program.shared", O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
if(SD< 0){
printf("\nshm_open() error \n");
return EXIT_FAILURE;
}
fchmod(SD, S_IRWXU|S_IRWXG|S_IRWXO);
if(ftruncate(SD, sizeof(MemData))< 0){
printf ("ftruncate() error \n");
return EXIT_FAILURE;
}
M=(struct MemData*)mmap(NULL, sizeof(MemData), PROT_READ|PROT_WRITE, MAP_SHARED, SD, 0);
if(M== MAP_FAILED){
printf("mmap() error");
return EXIT_FAILURE;
}else{
sem_init(&M->FullMutex, 1, 0);
sem_init(&M->FreeMutex, 1, NumberOfBuffers);
M->FileEnding=0;
M->ReadPointer=0;
M->WritePointer=0;
memset(M->Data, '\0', strlen(M->Data));
}

FILE *FP= fopen(FileName, "rb");
if(FP!= NULL){
struct stat StatBuf;
if(stat(FileName, &StatBuf)==-1){
printf("failed to fstat %s\n", FileName);
exit(EXIT_FAILURE);
}
long long FileSize=StatBuf.st_size;
printf("\nFile Size: %lld", FileSize);
long long FilePosition=ftell(FP);
FilePosition=ftell(FP);
long long CopyableMemorySize=FileSize-FilePosition;
printf("\nCopyable File Size: %lld", CopyableMemorySize);
int NumberOfFileBuffers=CopyableMemorySize/BufferSize;
printf("\nNumber Of File Buffers: %d\n", NumberOfFileBuffers);

//WRITE
while(1){
sem_wait(&M->FreeMutex);
fseek(FP, BufferCount*BufferSize, SEEK_SET);
fread(Buf, sizeof(unsigned char), BufferSize, FP);
int FreeMutexValue;
sem_getvalue(&M->FreeMutex, &FreeMutexValue);
int FullMutexValue;
sem_getvalue(&M->FullMutex, &FullMutexValue);
printf("\nMutexes-Free: %d and Full: %d", FreeMutexValue, FullMutexValue);
printf("\nBuffer Writing: %d", BufferCount);
memcpy(&M->Data[M->WritePointer*BufferSize], &Buf, sizeof(Buf)*sizeof(unsigned char));
BufferCount++;
M->WritePointer=(M->WritePointer+1)%NumberOfBuffers;
if(BufferCount>=NumberOfFileBuffers && M->WritePointer==M->ReadPointer){
M->FileEnding=1;
break;
}
sem_post(&M->FullMutex);
}
fclose(FP);
}
//close(SD);
return 0;
}

这是Reader.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>

int main(void){
char FileName[128]="bbb.txt";
struct MemData{
sem_t FullMutex;
sem_t FreeMutex;
int ReadPointer;
int WritePointer;
int FileEnding;
char Data[512000];//MEMORY BLOCK SIZE: 500 KB
};
int SD;
struct MemData *M;
int NumberOfBuffers=10;
//int BufferSize=51200;//FILE BUFFER SIZE 50 KB
int BufferSize=2;//EXPERIMENATION
unsigned char Buf[BufferSize];
int BufferCount=0;
SD= shm_open("/program.shared", O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
if(SD< 0){
printf("\nshm_open() error \n");
return EXIT_FAILURE;
}
M=(struct MemData*)mmap(NULL, sizeof(MemData), PROT_READ|PROT_WRITE, MAP_SHARED, SD, 0);
if(M== MAP_FAILED){
printf("mmap() error");
return EXIT_FAILURE;
}

FILE *FP= fopen(FileName, "wb");
if(FP!= NULL){

//READ
while(1){
sem_wait(&M->FullMutex);
int FreeMutexValue;
sem_getvalue(&M->FreeMutex, &FreeMutexValue);
int FullMutexValue;
sem_getvalue(&M->FullMutex, &FullMutexValue);
printf("\nMutexes-Free: %d and Full: %d", FreeMutexValue, FullMutexValue);
printf("\nBuffer Writing: %d", BufferCount);
printf("\nReadPointer: %d", M->ReadPointer);
printf("\nWritePointer: %d", M->WritePointer);
fseek(FP, BufferCount*BufferSize, SEEK_SET);
fwrite(&M->Data[M->ReadPointer*BufferSize], sizeof(unsigned char), BufferSize, FP);
BufferCount++;
M->ReadPointer=(M->ReadPointer+1)%NumberOfBuffers;
if(M->FileEnding){
fclose(FP);
break;
}
sem_post(&M->FreeMutex);
}
}
munmap(M,sizeof(MemData));
close(SD);
return 0;
}

Writer.c 的输出是
File Size: 50
Copyable File Size: 50
Number Of File Buffers: 25

Mutexes-Free: 9 and Full: 0
Buffer Writing: 0
Mutexes-Free: 8 and Full: 1
Buffer Writing: 1
Mutexes-Free: 7 and Full: 2
Buffer Writing: 2
Mutexes-Free: 6 and Full: 3
Buffer Writing: 3
Mutexes-Free: 5 and Full: 4
Buffer Writing: 4
Mutexes-Free: 4 and Full: 5
Buffer Writing: 5
Mutexes-Free: 3 and Full: 6
Buffer Writing: 6
Mutexes-Free: 2 and Full: 7
Buffer Writing: 7
Mutexes-Free: 1 and Full: 8
Buffer Writing: 8
Mutexes-Free: 0 and Full: 9
Buffer Writing: 9
Mutexes-Free: 0 and Full: 8
Buffer Writing: 10
Mutexes-Free: 2 and Full: 6
Buffer Writing: 11
Mutexes-Free: 1 and Full: 7
Buffer Writing: 12
Mutexes-Free: 0 and Full: 8
Buffer Writing: 13
Mutexes-Free: 0 and Full: 8
Buffer Writing: 14
Mutexes-Free: 0 and Full: 8
Buffer Writing: 15
Mutexes-Free: 0 and Full: 8
Buffer Writing: 16
Mutexes-Free: 1 and Full: 7
Buffer Writing: 17
Mutexes-Free: 0 and Full: 8
Buffer Writing: 18
Mutexes-Free: 0 and Full: 8
Buffer Writing: 19
Mutexes-Free: 0 and Full: 8
Buffer Writing: 20
Mutexes-Free: 0 and Full: 8
Buffer Writing: 21
Mutexes-Free: 0 and Full: 8
Buffer Writing: 22
Mutexes-Free: 0 and Full: 8
Buffer Writing: 23
Mutexes-Free: 0 and Full: 8
Buffer Writing: 24

Reader.c 的输出是
Mutexes-Free: 0 and Full: 9
Buffer Writing: 0
ReadPointer: 0
WritePointer: 0
Mutexes-Free: 1 and Full: 8
Buffer Writing: 1
ReadPointer: 1
WritePointer: 0
Mutexes-Free: 1 and Full: 8
Buffer Writing: 2
ReadPointer: 2
WritePointer: 1
Mutexes-Free: 2 and Full: 7
Buffer Writing: 3
ReadPointer: 3
WritePointer: 1
Mutexes-Free: 2 and Full: 6
Buffer Writing: 4
ReadPointer: 4
WritePointer: 2
Mutexes-Free: 1 and Full: 7
Buffer Writing: 5
ReadPointer: 5
WritePointer: 4
Mutexes-Free: 1 and Full: 8
Buffer Writing: 6
ReadPointer: 6
WritePointer: 5
Mutexes-Free: 1 and Full: 8
Buffer Writing: 7
ReadPointer: 7
WritePointer: 7
Mutexes-Free: 1 and Full: 8
Buffer Writing: 8
ReadPointer: 8
WritePointer: 7
Mutexes-Free: 1 and Full: 7
Buffer Writing: 9
ReadPointer: 9
WritePointer: 8
Mutexes-Free: 1 and Full: 8
Buffer Writing: 10
ReadPointer: 0
WritePointer: 9
Mutexes-Free: 1 and Full: 7
Buffer Writing: 11
ReadPointer: 1
WritePointer: 0
Mutexes-Free: 1 and Full: 8
Buffer Writing: 12
ReadPointer: 2
WritePointer: 1
Mutexes-Free: 1 and Full: 7
Buffer Writing: 13
ReadPointer: 3
WritePointer: 2
Mutexes-Free: 1 and Full: 8
Buffer Writing: 14
ReadPointer: 4
WritePointer: 3
Mutexes-Free: 1 and Full: 8
Buffer Writing: 15
ReadPointer: 5
WritePointer: 4

输入(aaa.txt)文件包含这些行 -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

输出(bbb.txt)文件包含这些行 -
1
2
3
4
5
6
7
8
9
10
11
12
13
14

最佳答案

您有许多小问题和指针的误用,但即使纠正了这些问题,您的作者/阅读者在复制文件时仍然会不一致 aaa.txtbbb.txt .为什么?当您读取文件并写入共享内存并从中展开时,互斥逻辑会采用不同的路径。

我们先来看看需要多少小修正。除非您提供 typedef , 你需要使用 struct MemData作为带有 sizeof 的类型,或者更好地使用指针本身。接下来,strlen(M->Data)无效,应为 sizeof (M->Data));当与:

    memset (M->Data, '\0', sizeof (M->Data));

接下来,您在使用 &Buf 时遇到了指针问题。在:
memcpy(&M->Data[M->WritePointer*BufferSize], &Buf, sizeof(Buf)*sizeof(unsigned char));
Buf已经是一个指针和 sizeof(unsigned char) == 1 .此外,如果您稍后分配 Buf而不是使用 VLA unsigned char Buf[BufferSize]; , sizeof (Buf)将是 sizeof (a_pointer) .更好地使用:
        memcpy (&M->Data[M->WritePointer*BufferSize], Buf, BufferSize);

在获得 FileSize 之后在 Writer.c 中与 StatBuf.st_size ,没有理由调用 ftell (FP)因为您没有使用 fseek 移动文件位置指示器该代码中的任何位置。同样在 Writer.c 中,没有理由调用 fseek (FP, BufferCount*BufferSize, SEEK_SET);因为您的阅读将随着每次阅读继续向前移动指示器。 (Reader.c 中的 fseek() 也有同样的问题)

另外 BufReader.c 中未使用的变量.

此外,您没有验证 fread (Buf, 1, BufferSize, FP); 的返回。或 fwrite (&M->Data[M->ReadPointer * BufferSize], 1, BufferSize, FP); .而在文件操作的情况下,您应该有 Buffersize 的竞争读取和写入。字节,不能保证,因此有必要检查返回(尤其是在读取具有奇数(51 字节)输入文件的 2 字节 block 时)。某处将读取或写入 1 个字节,如果您每次都盲目地写入 2 个字节,则某些事情将无法解决。

这将我们带到了您编写完整 bbb.txt 的问题的症结所在。 (或写入比 aaa.txt 更多的字节)使用 M->FileEnding作为指示输入结束的共享标志。这里有一个计数问题,我会让你解决。它从缓冲 10 开始(从文件中读取和)写入 Data在你开始阅读之前。您的 Writer.c计数器是 10Reader.c 的柜台前之前 Reader.c开始。这就是为什么在大多数运行中你有 16 Reader 的迭代次数当 Writer设置 M->FileEnding导致 Reader写入 bbb.txt 的前 32 个字节并退出。 (然后在足够多的运行中,您实际上将写入 Buffer Writing: 22 次,或 Buffer Writing: 27 次,从而产生 58 字节的 bbb.txt(所有数字都写入 1-20,然后在最后写入一些杂散的 0 秒)。

我提供了链接 考虑 5 Big Fat Reasons Why Mutexes Suck Big Time (第 2 篇文章)帮助解释围绕多线程代码可以采取的各种路径最终涵盖所有情况的陷阱。在这里,您拥有尽可能基本的逻辑,但仍然存在缓冲区在何时填充和何时卸载的问题 M->FileEnding标志被设置并被识别。花点时间回顾一下逻辑并确保您的 FullMutex , 和 FreeMutex逻辑正在做预期的事情。我的头顶上没有给你的 Elixir ,它需要逐个迭代地调试可以设置的可能组合——我把它留给你。

关于C Ring Buffer 共享内存信号量 ReadPointer WritePointer Not Right,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56266848/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com