C环形缓冲区共享内存信号量ReadPointer WritePointer不正确

时间:2019-05-23 01:11:06

标签: c ubuntu

我想使用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

2 个答案:

答案 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.cfread (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-200逻辑正在执行预期的工作。我头顶上没有银色的子弹,它会逐个迭代地调试可以设置的可能组合-我留给您。

答案 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;
}