1

我有两个线程

xThread:在控制台上连续打印 X

inputThread: 从标准输入获取输入

当用户输入“C”或“c”时,连续打印停止

#include<stdio.h>
#include<sys/select.h>
#include<pthread.h>
#define S sleep(0)

int read_c = 0;
pthread_mutex_t read_c_mutex = PTHREAD_MUTEX_INITIALIZER;

void* inputThread_fn(void* arg)
{
char inputChar;

while(1)
{
    S;

    printf("\nChecking input");
    scanf("%c",&inputChar);
    if(inputChar=='C' || inputChar == 'c')
    {
    pthread_mutex_trylock(&read_c_mutex); /*<--This must be _lock ?
    because with the use of trylock even If i don't aquire a lock I go ahead and modify
    the variable?*/
        read_c = 1;
    pthread_mutex_unlock(&read_c_mutex);        
    pthread_exit(NULL);
    }
}

}

void* xThread_fn(void* arg)
{
    while(1)
    {
        S;
    pthread_mutex_trylock(&read_c_mutex);
    if(!read_c)
    printf(" X");
    else
    pthread_exit(NULL);
    pthread_mutex_unlock(&read_c_mutex);
    }

}

void* yThread_fn(void* arg)
{
    while(1)
    {
        S;
    pthread_mutex_trylock(&read_c_mutex);
    if(!read_c)
    printf(" Y");
    else
    pthread_exit(NULL);
    pthread_mutex_unlock(&read_c_mutex);
    }

}


int main()
{
pthread_t xThread,yThread,inputThread;

pthread_create(&xThread,NULL,xThread_fn,NULL);
pthread_create(&inputThread,NULL,inputThread_fn,NULL);

pthread_join(xThread,NULL);
pthread_join(inputThread,NULL);

return 0;   
}

当我使用sleep(1)线程时,会产生线程并且[不管首先启动哪个线程],当程序到达scanfinputThread它会暂停用户输入,并且代码在我输入输入之前不会继续。

当我使用 执行代码时sleep(0)scanf不会停止输入,它会一直打印“X”,直到我输入“C”或“c”

sleep()以某种方式干扰吗scanf

注意:我知道select被用于非阻塞输入。我也尝试过,代码运行良好。我只想知道在上述情况下为什么会出现不一致的行为?


更新(使用trylock


 void* inputThread_fn(void* arg)
{
char inputChar;

    while(1)
    {
    S;
    scanf("%c",&inputChar);
        if(inputChar=='C' || inputChar == 'c')
        {
            pthread_mutex_trylock(&read_c_mutex);
                read_c = 1;
            pthread_mutex_unlock(&read_c_mutex);        
            pthread_exit(NULL);
        }
    }
}

void* xThread_fn(void* arg)
{
    while(1)
    {
    S;
    pthread_mutex_trylock(&read_c_mutex);
        if(!read_c)
        {
            pthread_mutex_unlock(&read_c_mutex);
            printf(" X");
        }
        else
        {
            pthread_mutex_unlock(&read_c_mutex);
            pthread_exit(NULL);
        }
    fflush(stdout); 
    }
}

void* yThread_fn(void* arg)
{
    while(1)
    {
    S;
    pthread_mutex_trylock(&read_c_mutex);
        if(!read_c)
        {
            pthread_mutex_unlock(&read_c_mutex);
            printf(" Z");
            fflush(stdout);
        }
        else
        {
            pthread_mutex_unlock(&read_c_mutex);
            pthread_exit(NULL);
        }
    }
}
4

1 回答 1

5

您看不到输出的原因是您没有刷新缓冲区。

您不需要刷新缓冲区的sleep(0)原因是因为写入器线程写入的数据太多以至于缓冲区填满并自动刷新。

#define SLEEP_TIME 1

void* xThread_fn(void* arg)
{
    while (1) {
        sleep(SLEEP_TIME);
        pthread_mutex_lock(&read_c_mutex);
        if (read_c) {
            pthread_mutex_unlock(&read_c_mutex);
            return NULL;
        }
        pthread_mutex_unlock(&read_c_mutex);
        printf(" X");
        fflush(stdout); // <-- necessary
    }
}

不要使用pthread_mutex_trylock()

不要pthread_mutex_trylock()在这里使用。这是错的。

lock()和之间的区别在于trylock()总是lock()会成功1trylock()有时会失败。这就是为什么它被称为“尝试”。

由于trylock()有时会失败,因此您必须处理失败的情况。您的代码无法处理这种情况:它只是向前推进,假装它获得了锁。所以,假设trylock()不锁定互斥锁。发生什么了?

pthread_mutex_trylock(&read_c_mutex);  // Might fail (i.e., not lock the mutex)
read_c = 1;                            // Modifying shared state (Wrong!)
pthread_mutex_unlock(&read_c_mutex);   // Unlocking a mutex (Wrong!)

然后是代码应该如何处理trylock()失败的问题。如果您无法回答这个问题,那么默认答案是“使用lock()”。

在阅读器线程中,您不能使用trylock(),因为您必须锁定互斥锁:

int r = pthread_mutex_trylock(&read_c_mutex);
if (r != 0) {
    // Uh... what are we supposed to do here?  Try again?
} else {
    read_c = 1;
    pthread_mutex_unlock(&read_c_mutex);
}

在作者线程中,使用没有意义trylock()

int r = pthread_mutex_trylock(&read_c_mutex);
if (r != 0) {
    // Okay, just try again next loop...
} else {
    if (read_c) {
        pthread_mutex_unlock(&read_c_mutex);
        pthread_exit(NULL);
    } else {
        pthread_mutex_unlock(&read_c_mutex);
    }
}

然而,这完全没有意义。写线程失败的唯一原因trylock()是读线程拥有锁,只有当它当前正在设置时才会发生这种情况read_c = 1;。所以你不妨等待它完成,因为你知道你无论如何都会退出(为什么在你知道用户已经通知你的程序停止之后还要写更多的输出?)

只需使用lock(). 您将使用lock()99% 的时间,并trylock()用于其他 1%。

1lock()函数可能会失败,但这通常意味着您滥用了互斥锁。

lock()关于和的误解trylock()

你说的是trylock()

如果我有另一个线程访问该变量read_input,那么使用它是否合适?

我认为这里对互斥锁的性质存在一个非常根本的误解。如果另一个线程没有同时访问该变量,那么您根本不需要互斥锁

假设你在办公室做重要的工作,你需要使用复印机。一次只能一个人使用复印机。你去复印机,有人已经在使用它了。

  1. 如果你排队等到轮到你,那就是lock()

  2. 如果您放弃并回到办公桌前,那就是trylock()。(您的程序实际上忽略了 的返回码trylock(),因此您基本上开始在复印机上捣碎按钮,即使其他人正在使用它。)

现在想象一下使用复印机需要一分钟,只有两个人使用过复印机,而且他们每二十年才使用一次复印机。

  1. 如果您使用,那么您在使用复印机之前最多lock()要排队等待一分钟。

  2. 如果您使用trylock(),那么您将放弃并回到办公桌前等待二十年,然后再次尝试复印机。

使用它没有任何意义trylock(),不是吗?您的线程是否如此急躁,以至于他们每二十年排一次队连一分钟都不能?

现在你的老板下来说:“我让你复印的那份报告呢?” 你说,“好吧,我六年前去过复印机,但有人在用它。”

这些数字(每 20 年一分钟)基于每个程序员都应该知道的延迟数字,其中指出锁定/解锁互斥体大约需要 25ns。因此,如果我们假装需要一分钟来锁定然后解锁互斥锁,那么sleep(1)就会导致线程等待二十年。

于 2013-04-04T14:38:56.767 回答