如何仅使用 pthread 互斥锁同步多个线程?

How could I synchronize multiple threads with only the use of pthread mutexes?

提问人:brocoli 提问时间:10/30/2023 更新时间:10/30/2023 访问量:61

问:

我试图制作三个线程,每个线程打开一个不同的输入文件,从中读取一个字符并将其设置为全局变量,然后等待下一个线程从它打开的文件中读取一个字符,并将其设置为该全局变量,然后移动到下一个线程。

总的来说,我打开了一个来写字符。因此,main 将只从全局变量中读取并按照 thread1、thread2、thread3、thread1、thread2、3..等读取的字符顺序写入文件。file.out.out

这是我到目前为止所拥有的:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>


//global char variables
char globalVAR1;
char globalVAR2;
char globalVAR3;

//define mutexes
pthread_mutex_t mutexOne;
pthread_mutex_t mutexTwo;
pthread_mutex_t mutexThree;


void *threadOne(void *arg){
    FILE *fileOne;
    fileOne = fopen("hw5-1.in", "r");

    char mChr1;

    //read each char
    if(fileOne == NULL){
        perror("file one error\n");
    }

    while(!feof(fileOne)){
        fscanf(fileOne, "%c\n", &mChr1);
        printf("char read: %c \n", mChr1);

        pthread_mutex_lock(&mutexOne);
        globalVAR1 = mChr1;
        pthread_mutex_unlock(&mutexOne);

    }

}

//thread two
void *threadTwo(void *arg){
    FILE *fileTwo;
    fileTwo = fopen("hw5-2.in", "r");

    char mChr2;

    //read each char
    if(fileTwo == NULL){
        perror("file two error\n");
    }

    while(!feof(fileTwo)){
        fscanf(fileTwo, "%c\n", &mChr2);
        printf("char read: %c \n", mChr2);

        pthread_mutex_lock(&mutexTwo);
        globalVAR2 = mChr2;
        pthread_mutex_unlock(&mutexTwo);

    }

}
//thread three
void *threadThree(void *arg){
    FILE *fileThree;
    fileThree = fopen("hw5-3.in", "r");

    char mChr3;

    //read each char
    if(fileThree == NULL){
        perror("file three error\n");
    }

    while(!feof(fileThree)){
        fscanf(fileThree, "%c\n", &mChr3);
        printf("char read: %c \n", mChr3);

        pthread_mutex_lock(&mutexThree);
        globalVAR3 = mChr3;
        pthread_mutex_unlock(&mutexThree);

    }

}

//main should open an out file for writing
int main(){

    //open a file for writing
    FILE *mainWriting;
    mainWriting = fopen("hw5.out", "w");

    FILE *count;
    count = fopen("hw5-1.in", "r");
    char cc;
    int nu=0;

    while(fscanf(count, "%c\n", &cc) == 1){
        nu += 1;
    }
    rewind(count);
    fclose(count);

    //write the global value into the outfile

    //the mutexes initialized
    pthread_mutex_init(&mutexOne, NULL);
    pthread_mutex_init(&mutexTwo, NULL);
    pthread_mutex_init(&mutexThree, NULL);

    pthread_t pthreadOne, pthreadTwo, pthreadThree;
    pthread_create(&pthreadOne, NULL, threadOne, NULL);
    pthread_create(&pthreadTwo, NULL, threadTwo, NULL);
    pthread_create(&pthreadThree, NULL, threadThree, NULL);


    while(nu != 0){
        //write into hw5.out
        pthread_mutex_lock(&mutexOne);
        fputc(globalVAR1, mainWriting);
        fputc('\n', mainWriting);
        pthread_mutex_unlock(&mutexOne);

        sleep(1);
    
        pthread_mutex_lock(&mutexTwo);
        fputc(globalVAR2, mainWriting);
        fputc('\n', mainWriting);
        pthread_mutex_unlock(&mutexTwo);

        sleep(1);
  
        pthread_mutex_lock(&mutexThree);
        fputc(globalVAR3, mainWriting);
        fputc('\n', mainWriting);
        pthread_mutex_unlock(&mutexThree);

        nu -=1;
    }


    sleep(1);
    pthread_join(pthreadOne, NULL);
    pthread_join(pthreadTwo, NULL);
    pthread_join(pthreadThree, NULL);

    fclose(mainWriting);

}

输入文件的行数相同,每行都有一个字符。

我的程序的输出预计为:

a
1
@
b
2
$
c
3
%

(输入文件实际上有点长。为简单起见,我没有包含整个输入文件。该程序应该处理任意长度的文件,假设它们都是相同的长度)

对于输入文件:

hw5-1.in

a
b
c

hw5-2.in

1
2
3

hw5-3.in

@
$
%

我只应该使用互斥锁来同步三个线程,而不使用标志、全局计数变量、信号量或条件。

我的输出是这样的:

c
3
%
c
3
%
c
3
%

我已经坚持了一段时间,我可能会把它弄得太复杂了,但不确定下一步该怎么做。我非常感谢任何建议或提示。谢谢。

C 多线程 pthreads 互斥锁

评论

0赞 John Bollinger 10/30/2023
代码中没有任何内容可以使额外的线程在读取字符后暂停,直到初始线程使用该字符。因此,毫不奇怪,在初始线程开始输出结果之前,三个附加线程中的每一个都读取其整个输入文件,一次一个字符 - 到那时,结果是每个文件的最后一个字符。
2赞 John Bollinger 10/30/2023
对于这项工作来说,单单是互斥锁就是一个非常糟糕的工具。信号量将是一个更好的选择,或者将条件变量与互斥锁相结合。无论如何,你必须确保每个读者都等待阅读第二个和后续字符,直到它收到某种肯定的确认,即作者已经使用了前一个字符。
0赞 0___________ 10/30/2023
@JohnBollinger 是 100% 正确的。请记住,您不知道线程的执行顺序。消费者必须同步它们

答:

1赞 0___________ 10/30/2023 #1

有 3 个互斥锁,它们将提供正确的读取器顺序。所有这些都由使用者线程锁定,并在它需要来自特定线程的数据时解锁。

另一个互斥锁保护全局变量。

共有 6 个互斥锁。3 表示正确的线程顺序,3 表示保护全局变量。

但是,仅使用互斥锁并不是实现它的最佳方式。

顺便说一句 您只能有一个全局变量。你不需要 3.

评论

0赞 brocoli 10/30/2023
这是否意味着两个不同的互斥锁将被解锁并锁定在每个线程的函数中,以获得正确的顺序?