同时使用条件变量和Mutex同步C语言中的线程

同时使用条件变量和Mutex同步C语言中的线程

本文介绍了同时使用条件变量和Mutex同步C语言中的线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据评论者的要求进行编辑.

Edited as per commenter's request.

该程序创建两个线程.每个线程从两个特定的输入文件之一读取,每个输入文件每行代码包含一个字母或一个"0".线程应该将字母读入全局char数组,然后将其打印.问题在于,一旦达到"0",活动线程就必须将控制权转移到另一个线程,该线程在该行上不应具有"0". (我们确定,如果文件1的一行上有一个"0",那么文件2的相应行上有一个字母.多个零可以跟在后面,多个字母也可以跟在后面.)

This program creates two threads. Each thread reads from one of two specific input files, each of which contains either one letter or one '0' per line of code. The threads are supposed to read the letters into a global char array, which is then printed. The problem is that, upon reaching a '0,' the active thread must transfer control to the other thread, which should not have a '0' on that line. (We are sure that, if File 1 has a '0' on a line, then File 2, on the corresponding line, has a letter. Multiple zeros can follow one another, as can multiple letters.)

一个文件

h
0
h
0
h
0
h
0
h
0

两个文件

0
i
0
i
0
i
0
i
0
i

我正在尝试使用pthread互斥锁进行锁定/解锁以及发出信号,并等待使其工作.但是,我一直处于僵局的状态.

I am attempting to use pthread mutex lock/unlock as well as signal and wait to make this work. However, I keep reaching a state of deadlock.

两个线程.目前,它们彼此镜像,这意味着它们执行相同的操作,只是使用不同的文件和相反的条件.

There are two threads. Currently, they mirror each other meaning that they do the same things, just with different files and opposite conditions.

线程示例:

char final[1001];
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t condition2 = PTHREAD_COND_INITIALIZER;

int w = 1;

void *get()
{
//start reading
while (count < //number)
{
    pthread_mutex_lock(&lock);

    //read line

    //if we've reached a zero
    {
        w = 2;

         while(w == 2)
         {
            pthread_cond_wait(&condition1, &lock);
         }


         pthread_mutex_unlock(&lock);
    }
    else
    {
       if(w == 1)
       {

            if(strlen(placeHolderChars)>0)
            {
                 placeHolderChars[1] = '\0';
            }

            //copy char to array

            w= 2;
            pthread_cond_signal(&condition2);
            pthread_mutex_unlock(&lock);
        }
    }

    if(feof(file))
    {
        fclose(file);
        break;
    }
    count++;

 }

return 0;
}

更新:使用更大的文件时,等待前信号策略并没有真正起作用.还在为此工作!

UPDATE: Signal-before-wait strategy did not really work when using a larger file. Still working on this!

推荐答案

此代码似乎有效.主要的重要变化是在进入while (who == N)循环之前,在另一个线程的条件上添加pthread_cond_signal().

This code seems to work. The primary significant change is to add pthread_cond_signal() on the the other thread's condition before going into the while (who == N) loops.

其他更改包括基本的调试打印,可以更轻松地查看哪个线程在做什么.请注意,调试消息以换行符结尾.

Other changes include basic debug printing to make it easier to see what's going on an which thread is doing what. Note that debugging messages end with newlines.

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

extern void *getMessage1(void *arg);
extern void *getMessage2(void *arg);

static char message[4096];

int main(void)
{
    pthread_t id1;
    pthread_t id2;

    pthread_create((&id1), NULL, getMessage1, NULL);
    pthread_create((&id2), NULL, getMessage2, NULL);

    pthread_join(id1, NULL);
    pthread_join(id2, NULL);

    for (int j = 0; j < 1001 && message[j] != '\0'; j++)
        printf("%c ", message[j]);
    putchar('\n');

    return 0;
}

static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t condition1 = PTHREAD_COND_INITIALIZER;
static pthread_cond_t condition2 = PTHREAD_COND_INITIALIZER;

static int who = 1;

void *getMessage1(void *arg)
{
    assert(arg == NULL);
    const char filename[] = "Student1";
    FILE *studentOne = fopen(filename, "r");
    if (studentOne == NULL)
    {
        fprintf(stderr, "Failed to open file %s for reading\n", filename);
        exit(EXIT_FAILURE);
    }

    size_t howManyChars;
    char *placeHolderChars;
    int count = 1;

    while (count < 501)
    {
        placeHolderChars = NULL;
        if (getline(&placeHolderChars, &howManyChars, studentOne) == -1)
            break;
        printf("M1(%d): [%s]\n", count, placeHolderChars);
        pthread_mutex_lock(&lock);
        if (strcmp(placeHolderChars, "0\n") == 0)
        {
            printf("M1: Two's turn - 1\n");
            pthread_cond_signal(&condition2);
            who = 2;
            while (who == 2)
            {
                pthread_cond_wait(&condition1, &lock);
            }
            free(placeHolderChars);
        }
        else
        {
            if (who == 1)
            {
                if (strlen(placeHolderChars) > 0)
                {
                    placeHolderChars[1] = '\0';
                }
                strcat(message, placeHolderChars);
                free(placeHolderChars);
                who = 2;
                pthread_cond_signal(&condition2);
            }
            else
                printf("M1: Two's turn - 2\n");
        }
        pthread_mutex_unlock(&lock);
        count++;
    }

    fclose(studentOne);
    return 0;
}

void *getMessage2(void *arg)
{
    assert(arg == NULL);
    const char filename[] = "Student2";
    FILE *studentTwo = fopen(filename, "r");
    if (studentTwo == NULL)
    {
        fprintf(stderr, "Failed to open file %s for reading\n", filename);
        exit(EXIT_FAILURE);
    }

    size_t howManyChars;
    char *placeHolderChars;
    int count = 0;

    while (count < 501)
    {
        placeHolderChars = NULL;
        if (getline(&placeHolderChars, &howManyChars, studentTwo) == -1)
            break;
        printf("M2(%d): [%s]\n", count, placeHolderChars);
        pthread_mutex_lock(&lock);
        if (strcmp(placeHolderChars, "0\n") == 0)
        {
            printf("M2: One's turn - 1\n");
            pthread_cond_signal(&condition1);
            who = 1;
            while (who == 1)
            {
                pthread_cond_wait(&condition2, &lock);
            }
            free(placeHolderChars);
        }
        else
        {
            if (who == 2)
            {
                if (strlen(placeHolderChars) > 0)
                {
                    placeHolderChars[1] = '\0';
                }
                strcat(message, placeHolderChars);
                free(placeHolderChars);
                who = 1;
                pthread_cond_signal(&condition1);
            }
            else
                printf("M2: One's turn - 2\n");
        }
        pthread_mutex_unlock(&lock);
        count++;
    }

    fclose(studentTwo);
    return 0;
}

您应该能够完善代码,以便将包含相关的每线程数据(文件名,当前线程条件,其他线程条件,可能是线程ID")的结构传递给单个函数,因此您只是getMessage().

You should be able to refine the code such that you pass a structure containing the relevant per-thread data (file name, current thread condition, other thread condition, maybe a 'thread ID') to a single function, so you have just getMessage().

输出:

M1(1): [h
]
M2(0): [0
]
M1(2): [0
]
M2: One's turn - 1
M1: Two's turn - 1
M2(1): [i
]
M2(2): [0
]
M2: One's turn - 1
M1(3): [h
]
M1(4): [0
]
M1: Two's turn - 1
M2(3): [i
]
M2(4): [0
]
M2: One's turn - 1
M1(5): [h
]
M1(6): [0
]
M1: Two's turn - 1
M2(5): [i
]
M2(6): [0
]
M2: One's turn - 1
M1(7): [h
]
M1(8): [0
]
M1: Two's turn - 1
M2(7): [i
]
M2(8): [0
]
M2: One's turn - 1
M1(9): [h
]
M1(10): [0
]
M1: Two's turn - 1
M2(9): [i
]
h i h i h i h i h i


我对这段代码并不完全满意.正如我暗示的那样,我创建了一个修改后的版本,并且两个线程都使用了一个函数,并修改了读取行的打印,以避免打印换行符(使输出更紧凑).有时-并非总是如此-最终将陷入僵局.两种示例跟踪,一种工作,一种死锁(程序名称pth47):

$ pth47
M2(1): [0]
M2: 1's turn - 1
M1(1): [h]
M1(2): [0]
M1: 2's turn - 1
M2(2): [i]
M2(3): [0]
M2: 1's turn - 1
M1(3): [h]
M1(4): [0]
M1: 2's turn - 1
M2(4): [i]
M2(5): [0]
M2: 1's turn - 1
M1(5): [h]
M1(6): [0]
M1: 2's turn - 1
M2(6): [i]
M2(7): [0]
M2: 1's turn - 1
M1(7): [h]
M1(8): [0]
M1: 2's turn - 1
M2(8): [i]
M2(9): [0]
M2: 1's turn - 1
M1(9): [h]
M1(10): [0]
M1: 2's turn - 1
M2(10): [i]
h i h i h i h i h i
$ pth47
M1(1): [h]
M2(1): [0]
M1(2): [0]
M2: 1's turn - 1
M1: 2's turn - 1
M2(2): [i]
M2(3): [0]
M2: 1's turn - 1
M1(3): [h]
M1(4): [0]
M1: 2's turn - 1
M2(4): [i]
M2(5): [0]
M2: 1's turn - 1
M1(5): [h]
M1(6): [0]
M1: 2's turn - 1
M2(6): [i]
M1(7): [h]
M1(8): [0]
M2(7): [0]
M1: 2's turn - 1
M2: 1's turn - 1
M1(9): [h]
M1(10): [0]
M2(8): [i]
M1: 2's turn - 1
M2(9): [0]
M2: 1's turn - 1
^C
$

我没有找到像差.这并不像线程先行"那么简单.在某些例子中,线程一是第一个进入线程并且完成得很好.

I've not tracked down the aberration. It isn't as simple as 'thread one went first'; there are examples where thread one went first and it completed fine.

这篇关于同时使用条件变量和Mutex同步C语言中的线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-29 19:18