我想使用Reader-Writer Synchronization Paradigm构建文件复印机。 Writer初始化两个互斥对象。 FullMutex表示可用于写入的缓冲区数量,而FreeMutex表示可用于读取的缓冲区数量。 当块已满时,编写器将等待。 WritePointer和ReadPointer正在使用环形缓冲区。因此,我使用了Mod Operation。 块大小= M。 缓冲区大小= B。 有N个缓冲区。 因此,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会以这种方式出现?
这是作家。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;
}
这是读者。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
input(aaa.txt)文件包含以下行-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
output(bbb.txt)文件包含以下行-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
答案 0 :(得分:2)
您有很多小问题,并且滥用了指针,但是即使更正了这些问题,您的作者/读者在将文件aaa.txt
复制到bbb.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
中获得StatBuf.st_size
后,在Writer.c中,没有理由调用ftell (FP)
,因为您没有使用{{1}移动文件位置指示器}在该代码中的任何位置。同样在Writer.c中,也没有理由调用fseek
,因为您的读取将随着每次读取而继续将指示器向前移动。 (Reader.c中的fseek (FP, BufferCount*BufferSize, SEEK_SET);
也有同样的问题)
另外fseek()
是Buf
中未使用的变量。
此外,您没有验证Reader.c
或fread (Buf, 1, BufferSize, FP);
的返回。对于文件操作,您应该具有fwrite (&M->Data[M->ReadPointer * BufferSize], 1, BufferSize, FP);
个字节的读写权限,但这不能保证,因此有必要检查返回值(尤其是在读取带有 odd < / em>(51字节)输入文件)。在某个地方会有一个1字节的读取或写入,如果您每次盲目地写入2字节,都将无法解决问题。
使用Buffersize
作为指示输入结束的共享标志,编写完整的bbb.txt
(或写入比aaa.txt
多的字节)的问题,使我们陷入困境。这里有一个计数问题,我将让您解决。它在您开始读取之前缓冲M->FileEnding
(从文件读取并)写入10
时开始。 Data
开始之前,您的Writer.c
计数器比10
中的计数器Reader.c
早。这就是为什么在大多数运行中,当Reader.c
设置16
导致Reader
写入{{1}的前32个字节时,Writer
迭代了M->FileEnding
},然后退出。 (然后,在足够多的运行中,您实际上将写入Reader
次,或bbb.txt
次,导致58字节的Buffer Writing: 22
(写入了所有数字Buffer Writing: 27
,然后有一些杂散的{末尾有{1}}个。
我提供了链接“ 5 Big Fat Reasons Why Mutexes Suck Big Time”(第二篇文章),以帮助解释有关多线程代码可以采用的各种路径的所有情况的隐患。在这里,您已具备了尽可能多的逻辑基础,但是仍然存在一些问题,其中,当设置并识别bbb.txt
标志时,何时填充缓冲区以及何时卸载缓冲区。请花些时间回顾一下逻辑,并确保您的1-20
和0
逻辑正在执行预期的工作。我头顶上没有银色的子弹,它会逐个迭代地调试可以设置的可能组合-我留给您。
答案 1 :(得分:0)
MemData已更改,以跟踪已写入或读取了多少缓冲区。
这是作家。c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.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 NumberOfFileBuffers;
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(struct MemData))< 0){
printf ("ftruncate() error \n");
return EXIT_FAILURE;
}
M=(struct MemData*)mmap(NULL, sizeof(struct MemData), PROT_READ|PROT_WRITE, MAP_SHARED, SD, 0);
if(M== MAP_FAILED){
printf("mmap() error");
return EXIT_FAILURE;
}else{
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=ceil(CopyableMemorySize/BufferSize);
printf("\nNumber Of File Buffers: %d\n", NumberOfFileBuffers);
//INITIALIZATION
sem_init(&M->FullMutex, 1, 0);
sem_init(&M->FreeMutex, 1, NumberOfBuffers);
M->ReadPointer=0;
M->WritePointer=0;
M->NumberOfFileBuffers=NumberOfFileBuffers;
memset(M->Data, '\0', sizeof(M->Data));
//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\n", FreeMutexValue, FullMutexValue);
printf("\nBuffer Writing: %d\n", BufferCount);
memcpy(&M->Data[M->WritePointer*BufferSize], Buf, BufferSize);
BufferCount++;
M->WritePointer=(M->WritePointer+1)%NumberOfBuffers;
sem_post(&M->FullMutex);
if(BufferCount==M->NumberOfFileBuffers){
fclose(FP);
break;
}
//sem_post(&M->FullMutex);
}
}
close(SD);
}
return 0;
}
这是读者。c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.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 NumberOfFileBuffers;
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(struct MemData), PROT_READ|PROT_WRITE, MAP_SHARED, SD, 0);
if(M== MAP_FAILED){
printf("mmap() error");
return EXIT_FAILURE;
}else{
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 and WritePointer: %d", M->ReadPointer, M->WritePointer);
printf("\nBuffer Writing: %d\n", BufferCount);
fseek(FP, BufferCount*BufferSize, SEEK_SET);
fwrite(&M->Data[M->ReadPointer*BufferSize], sizeof(unsigned char), BufferSize, FP);
BufferCount++;
M->ReadPointer=(M->ReadPointer+1)%NumberOfBuffers;
sem_post(&M->FreeMutex);
if(BufferCount==M->NumberOfFileBuffers){
fclose(FP);
break;
}
//sem_post(&M->FreeMutex);
}
}
munmap(M,sizeof(struct MemData));
close(SD);
}
return 0;
}