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)线程产生并且[无论哪个线程首先被启动]当程序到达scanf时inputThread它停止用户输入并且代码在我输入输入之前不会继续.
当我执行代码时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)
您没有看到输出的原因是因为您没有刷新缓冲区.
您不需要刷新缓冲区的原因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那么它是否适合使用它?
我认为这里存在一个关于互斥体性质的非常根本的误解.如果另一个线程没有同时访问该变量,那么根本不需要互斥锁.
假设你在办公室做重要的工作,你需要使用复印机.一次只能有一个人使用复印机.你去复印机,有人已经在使用它.
如果你排队等候轮到你,那就是lock().
如果你放弃并回到你的办公桌,那就是trylock().(您的程序实际上忽略了返回代码trylock(),因此即使其他人正在使用它,您基本上也会开始在复印机上粘贴按钮.)
现在想象一下,使用复印机需要一分钟,只有两个人使用复印机,而且他们每二十年才使用一次复印机.
如果您使用lock(),则在使用复印机之前排队等候最多一分钟.
如果您使用trylock(),那么您放弃并回到办公桌前等待二十年才再次尝试复印机.
使用它没有任何意义trylock(),是吗?你的线程是否如此不耐烦,以至于他们每20年就不能花一分钟排队?
现在你的老板下来说:"我要求你复印哪份报告?" 你说,"好吧,六年前我去了复印机,但是有人在用它."
数字(每二十年一分钟)基于每个程序员应该知道的延迟数,它指出锁定/解锁互斥锁大约是25ns.因此,如果我们假装锁定然后解锁互斥锁需要一分钟,那么sleep(1)该线程会等待二十年.