【问题标题】:Mutex file reading synchronization互斥文件读取同步
【发布时间】:2018-10-15 23:43:30
【问题描述】:

我正在尝试同步读取 5 个文件,以便从一个文件中读取每个字符,然后从下一个文件中读取另一个字符,依此类推。最后一个数组将打印出内容。我可以从文件中读取,但同步已经结束。我试图用一个控制变量来修复它,只在文件打开时运行代码块,但我得到一个不稳定的输出。这是我在关键部分工作的部分

while(!feof(drive1)) {
        if(control == 0) {
            pthread_mutex_lock(&thread1);
            //printf("Mutex lock\n");
            c = getc(drive1);
            printf("%c", (char)c);
            control = 1;
            pthread_mutex_unlock(&thread1);
            //printf("Mutex unlock\n");
        } else if(control == 1) {
            pthread_mutex_lock(&thread2);
            //printf("Mutex lock\n");
            a = getc(drive2);
            printf("%c", (char)a);
            control = 2;
            pthread_mutex_unlock(&thread2);
            //printf("Mutex unlock\n");
        } else if(control == 2) {
            pthread_mutex_lock(&thread3);
            //printf("Mutex lock\n");
            b = getc(drive3);
            printf("%c", (char)b);
            control = 3;
            pthread_mutex_unlock(&thread3);
            //printf("Mutex unlock\n");
        } else if(control == 3) {
            pthread_mutex_lock(&thread4);
            //printf("Mutex lock\n");
            d = getc(drive4);
            printf("%c", (char)d);
            control = 4;
            pthread_mutex_unlock(&thread4);
            //printf("Mutex unlock\n");
        } else if(control == 4) {
            pthread_mutex_lock(&thread5);
            //printf("Mutex lock\n");
            e = getc(drive5);
            printf("%c", (char)e);
            control = 0;
            pthread_mutex_unlock(&thread5);
            //printf("Mutex unlock\n");
        }

我最初尝试只使用一个线程 1 来锁定和解锁互斥锁,但后来决定创建 5 个线程来查看是否有帮助,但它没有。我还必须为每个文件使用 5 个线程来执行此操作。

pthread_t th1;
    pthread_create(&th1, NULL, processing, NULL);
    pthread_t th2;
    pthread_create(&th2, NULL, processing, NULL);
    pthread_t th3;
    pthread_create(&th3, NULL, processing, NULL);
    pthread_t th4;
    pthread_create(&th4, NULL, processing, NULL);
    pthread_t th5;
    pthread_create(&th5, NULL, processing, NULL);
    pthread_join(th1, NULL);
    pthread_join(th2, NULL);
    pthread_join(th3, NULL);
    pthread_join(th4, NULL);
    pthread_join(th4, NULL); 

这是我得到的输出

输出应该是“1234567890abcdefghij”

更新:基于其中一个 cmets,我修改了代码以使用变量“test”作为关键部分中正在测试的内容。使用此代码,我得到输出 1212。​​

void* disk1(void* args) {
    //Initializing array of files
    FILE *drive[5];

    drive[0] = fopen("drive1.data", "r");
    drive[1] = fopen("drive2.data", "r");
    drive[2] = fopen("drive3.data", "r");
    drive[3] = fopen("drive4.data", "r");
    drive[4] = fopen("drive5.data", "r");


    int c;

    if(test < initialFileSize * 2) {
        pthread_mutex_lock(&thread1);
        if(test % 2 == 0) {
            c = getc(drive[0]);
            printf("%c", (char)c);
            test++;
        }
        if(test % 2 == 1) {
            c = getc(drive[1]);
            printf("%c", (char)c);
            test++;
        }
        pthread_mutex_unlock(&thread1);
    }
}

【问题讨论】:

  • 你认为互斥体应该做什么?他们只确保 lock() 和 unlock() 之间的语句发生在一个线程中。他们没有做任何事情来确保线程被赋予相同的时间片,或者以任何特定的顺序运行。
  • 那么我将如何实施某种计划。我们不允许使用信号量。
  • 由于每个线程只查看自己的互斥体,因此没有太多的互斥。而且由于所有线程都查看共享资源control 而不确保互斥,因此任何人都可以猜测任何给定进程会看到什么。在我的脑海中,我认为您可能需要查看具有单个互斥锁控制对control 的访问的条件变量,以及锁定互斥锁的线程,等待条件,测试control 是否设置为它们的值(如果没有,则再次等待),并在值指示轮到他们时继续。

标签: c synchronization mutex file-read


【解决方案1】:

您可以将它们与单个标志同步,但它们会花费大部分时间等待,因此这可能不是最佳选择:

char shouldRead(){
  static unsigned int activeThread = 0; //used as index into the file to read and the thread compare.
  char x = 0;

  //wait for mutex
  pthread_mutex_lock(&readVariableMutex);
  //acquired mutex

  //read variable to see what thread should run
  if(availableThreads[activeThread] == myThreadId){
    x = getc(drive[activeThread]); //or w/e your doing when it should run
    activeThread++;
    activeThread %= MAX_THREADS; //should be 5 right
  }

  pthread_mutex_unlock(&readVariableMutex);
  return x;
}

//where ever you spawn your threads add them to a global availableThreads[MAX_THREADS] array;
//Also, when you intialize your FILE *'s, add them to a drive array.
//The above idea is to wrap access to variable "activeThread" around the mutex such that the controlling thread will always be the next thread, or it will do nothing and release the mutex.

所有线程都会有类似的东西:

while(!eof(drive[thead_id])){ //Each thread needs to know when its at end of file somehow
  printf("%c",shouldRead());
}

【讨论】:

  • 请注意,readVariableMutex 将在您生成 5 个线程(大概在 main 中)之前被初始化,并且不是线程而是 pthread_mutex_t 类型。
【解决方案2】:

有几点需要考虑:

  • if(control == 0):if 条件放置错误。当线程开始执行函数时,counter 等于 0。因此,很可能有多个线程进入 if 条件。
  • 在下一行中,您将锁定互斥锁。但是可能有线程已经进入了 if 条件。 Mutext 只是让线程一个接一个地执行下一行。因此,每个线程一个接一个地进入 drive1 并从中读取并打印第一个字符。这就是原因,你得到输出“11111”
  • 其他 else if 语句也是如此,您将得到输出“111112222233333 ...”
  • while(!feof(drive1)):while 条件正在检查文件 drive1 的文件结尾。根据 drive1 中的字符数,它将循环。相反,检查单个文件或检查要打印的字符总数会得到更准确的结果。

几点可能会有所帮助:

  • 互斥锁或任何其他锁用于同步对共享资源或变量或代码块的访问。可能有多个线程试图访问代码块或变量/资源。但是,所需的互斥锁数量取决于您希望同步的变量或代码块的数量。
  • 在这种情况下,预期的输出是一个特定的序列。这可以通过同步对整个块的访问来实现,其中检查计数器值并读取特定文件并将其写入标准输出。所以,我们有一个代码块作为关键部分,我们需要一个互斥锁。
  • 如果保护在多个函数中使用的共享变量/资源。我们需要使用一个互斥锁来保护所有函数中的一个变量/资源。

请在检查条件 if(control == 0) 之前锁定互斥锁,并在完成最后一个 else if 后解锁。它将同步对代码块的访问。还需要改变while(!feof(drive1))条件。

下面给出了一种解决方法。

  • 我已经使用了 while 条件下要打印的字符总数。
  • 使用“total”作为可变变量。
  • 在while循环中再次检查“total”的值,有可能是线程进入临界区时total的值发生了变化。
  • 使用此解决方案,同一线程可能会再次获得锁并打印值。

            while(total < TOTAL_CHAR_TO_PRINT)
            {
                    pthread_mutex_lock(&m1);
                    if(total >= TOTAL_CHAR_TO_PRINT)
                    {
                            pthread_mutex_unlock(&m1);
                            return 0;
                    }
    
                    counter = counter % NUM_OF_FILES;
                    d = fgetc(fptr[counter]);
                    printf("%c", d);
    
                    counter += 1;
                    total += 1;
    
                    pthread_mutex_unlock(&m1);
            }
    

【讨论】:

  • 感谢您的详细回复。虽然我还没有尝试过,但我会及时更新。我忘了提及,但我使用 feof(drive1) 的原因是因为每个驱动器文件的长度相同。因此,当从驱动器 1 读入一个字符时,我希望它从其他驱动器执行相同的操作。这是我最初的逻辑。
  • 是的,它似乎在这种情况下有效。但是,如果您在 drive1 中错误地添加了一个空格,但其余文件已经到达文件末尾,则很容易出错。此外,您需要在 while 循环中再次检查正在等待互斥锁的线程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-10
  • 2014-05-02
  • 1970-01-01
  • 2012-04-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多