sleep()会干扰scanf()吗?

Suv*_*yil 1 c linux sleep pthreads scanf

我有两个主题

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

inputThread:从stdin获取输入

当用户输入"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;   
}
Run Code Online (Sandbox Code Playgroud)

当我使用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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Die*_*Epp 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
    }
}
Run Code Online (Sandbox Code Playgroud)

不要用 pthread_mutex_trylock()

不要pthread_mutex_trylock()在这里使用.这是不对的.

之间的区别lock()trylock()lock()永远成功1,但trylock()有时会失败.这就是为什么它被称为"尝试".

由于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!)
Run Code Online (Sandbox Code Playgroud)

然后是代码应该如何处理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);
}
Run Code Online (Sandbox Code Playgroud)

在作者线程中,使用时没有意义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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,这完全没有意义.trylock()写入器线程中唯一的原因是读取器线程拥有锁定,只有当它正在设置过程中才会发生read_c = 1;.所以你不妨等待它完成,因为你知道你将要退出(为什么在你知道用户已经发出信号停止后会写出更多输出?)

只是用lock().您将使用lock()99%的时间,而trylock()另一个则使用1%.

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

lock()和的误解trylock()

你说的是这样的trylock():

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

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

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

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

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

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

  1. 如果您使用lock(),则在使用复印机之前排队等候最多一分钟.

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

使用它没有任何意义trylock(),是吗?你的线程是否如此不耐烦,以至于他们每20年就不能花一分钟排队?

现在你的老板下来说:"我要求你复印哪份报告?" 你说,"好吧,六年前我去了复印机,但是有人在用它."

数字(每二十年一分钟)基于每个程序员应该知道的延迟数,它指出锁定/解锁互斥锁大约是25ns.因此,如果我们假装锁定然后解锁互斥锁需要一分钟,那么sleep(1)该线程会等待二十年.