打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
pthread
1.   pthread条件变量使用范式
pthread_cond_t在解决同步问题时非常有用,但是由于线程同步问题的复杂性,pthread_cont_t的使用也有一定技巧。
1.1. 模型1
在多线程竞争临界资源时,用pthread_cond_wait和pthread_cond_signal机制。典型做法是,在使用资源的线程里,判断资源是否可用;如果不可用,则调用pthread_cond_wait将自身阻塞;在另一个生产资源的线程里,如果发现资源可用了,则调用pthread_cond_signal或者pthread_cond_broadcast唤醒在等待资源的线程。可以看出,pthread条件变量简直天然地适合解决“生产者-消费者”问题。用伪代码表示如下:
生产者:
pthread_mutex_lock();
resource++;                     //资源增加
pthread_cond_signal();
pthread_mutex_unlock();
消费者
pthread_mutex_lock();
if(resource NOT available)
pthread_cond_wait();          //执行到此处线程被阻塞
//其他线程调用pthread_cond_signal唤醒该线程后得到执行
resource--;
handle resource
pthread_mutex_unlock();
在wait和signal的前后加上互斥锁的目的在于保护临界资源。
1.2. 模型2
问题来了:对消费者来说,在wait返回(也就是被消费者线程被唤醒)后,资源是否就一定可用呢?
1.2.1.    各种类型的生产者-消费者问题
生产者-消费者问题分为多种类型:
生产者数
消费者数
竞争条件
考虑问题
1
1
生产者和消费者竞争
通过对临界资源的互斥访问解决,消费者被唤醒后资源一定有效。
1
N
1、生产者和消费者竞争
2、消费者间存在竞争
1、  临界资源的互斥访问
2、  生产者到底唤醒哪一个消费者
3、  唤醒后资源是否已经被其他消费者占用
N
1
1、生产者和消费者竞争
2、生产者间存在竞争
通过对临界资源的互斥访问解决,消费者被唤醒后资源一定有效。
N
M
1、生产者和消费者竞争
2、消费者间存在竞争
3、生产者间存在竞争
上述所有因素
由上表可知,当存在多个相互竞争的消费者时,wait返回后,有可能资源已经被其他消费者占用了。所以应该再次判断资源是否有效。
1.2.2.    pthread_cond_wait详细执行过程
wait实际上是个复杂的分解动作,包括如下步骤:
1)解锁。因为在wait被调用之前,已经加锁了;如果此处不解锁的话,生产者就无法进入临界区增加资源。这就是pthread_cond_wait中需要mutex作为参数之一的原因。
2)阻塞。
3)加锁。阻塞被解除之后,接下来消费者应该要去访问临界资源,所以要先对其加锁。
由于wait分为若干步骤,期间很容易让其他消费者横插一杠子。比如在步骤2和3之间。步骤2结束说明已有资源可用,且未被加锁;其他消费者可以抢先加锁,消耗资源,解锁;然后本消费者执行步骤3加锁,但是这时已无资源可用。
1.2.3.    无效signal
当生产者发出pthread_cond_signal,而此时没有消费者在wait时,signal就会丢失,后面再次调用wait就等不到signal了。这点已经在linux/vxworks上都得到验证。
造成这种情况,一般不是因为没有在消费者中调用wait,多半是由于消费者在wait之后忙于读取处理资源,而signal正好在这个时候被发送。在多线程并发情况下,wait和signal的顺序往往得不到保证,所以很可能出现无效signal。
1.2.4.    本质论
由上分析可知,wait-signal只是通知机制,并不代表资源本身的情况,需要我们用一定的手段或者技巧去检查和保证资源的可用情况。模型2可以较好解决上述问题:
消费者:
pthread_mutex_lock();
while(TRUE)
{
if(resource IS available)
{
resource--;        //消耗资源
handle resource;  //处理资源
break;
}
pthread_cond_wait();
}
pthread_mutex_unlock();
1.3. 模型3
在模型2的“资源消耗和处理”步骤中,一般分两步:
1)从共享数据区读取数据
2)处理数据
如果处理数据的过程比较耗时,就可能导致生产者和其他消费者长时间等待。为了提高效率,可以将资源数据从共享区拷贝出来,将处理数据的步骤放到pthread_mutex_unlock之后去做。
消费者:
while(TRUE)
{
pthread_mutex_lock();
while(TRUE)
{
if(resource IS available)
{
resource--;              //资源消耗
break;
}
pthread_cond_wait();
}
pthread_mutex_unlock();
handle resource;            //资源处理
}
模型2不存在无效signal 的问题,因为在对资源的处理结束之前,生产者是无法进入临界区的,也就无法调用signal。而模型3就可能存在无效signal的问题,但是不会影响整体的正常运行。虽然signal没有得到响应,但是消费者处理完毕数据后,再次检查资源是否可用时,发现仍然有可用资源,于是再次读取、处理。
2.   生产者-消费者问题在驱动开发中的实现
硬件通信在基本实现结构上,无外乎轮询和中断两种方式。对轮询方式,程序不断地检查通信接口上是否有数据到来,若有则从硬件缓存中读取数据、处理。
中断方式下,不用程序去循环检查硬件状态,当有数据到来时,通过中断通知程序去读取缓存中的数据。由于中断处理程序的编写要求是执行得越快越好,所以中断处理程序中做的主要工作只是把数据从硬件缓存中读取到host内存中。对于被读数据的解析和处理留给中断下半部完成。在不同的系统中,上述工作的实现细节差异很大。
在linux中,对中断下半部有明确的定义和支持,比如softirq、tasklet和workqueue等。直接使用上述组件即可。
在vxworks 5.5中,没有明确地提出下半部的概念,耗时操作如何处理完全由开发者自行决定。在自己做的1394协议栈中是这样设计的(相信这也是个普遍的思路)。
创建一个独立的内核线程tComm,并申请一片足够大的空间作为数据缓存buffer。tComm循环读取buffer中的数据,发现buffer为空,则tComm睡眠,不空则读取buffer中的数据并处理。当数据到来时,中断处理程序拷贝硬件缓存中的数据到buffer中,并将tComm唤醒。
从上面的描述可以看到,中断处理程序相当于生产者,内核线程tComm相当于消费者。由于vxworks没有内核和应用之分,应用程序可以直接访问硬件,所以可以用pthread来实现前面描述的内核线程,以及相关同步操作。
3.   中断和线程如何同步-模型4
中断和线程共享数据缓存区buffer,和中断共享数据时不能用模型2和3。中断与线程的同步问题和线程间的同步略有不同。线程间进行同步时,使用互斥量保护临界区。而中断处理程序不允许睡眠,也就不许使用同步原语(如pthread_mutex_lock),唯一的互斥手段就是开/关中断。要注意的是,关中断的时间要尽可能短,否则会影响系统实时性。
生产者(中断处理程序):
(中断到来)
if(resource IS available)
{
Read resource from hardware;
Copy resource to shared buffer;
pthread_cond_signal();
}
消费者(线程):
while(TRUE)
{
while(resource NOT available)
{
pthread_mutex_lock();
pthread_cond_wait();
pthread_mutex_unlock();
}
关中断;
resource--;
开中断;
handle resource;            //资源处理
}
注意,在handle resource消耗时间较长,而中断频率较高时,中断会发出无效signal。
编译:pthread_cond_t解决生产者-消费者问题
地址:http://www.07net01.com/program/65658.html
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
关于 多线程中互斥锁和条件锁的理解
pthread_cond_signal()的具体位置?
pthread条件变量函数的使用
pthread_cond_signal虚假唤醒(spurious wakeup)
pthread_cond_wait().
pthread_cond_wait() 前使用 while 讲解
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服