使用信号量

使用信号量

标签信号量  2009-01-08 23:37
信号量是非负的整型计数,用于协调对多个资源的访问。如果你获取了信号量,计数就会减少;释放信号量,计数就会增大。如果计数达到0--不在有资源 --试图获取该信号量的线程就会阻塞,直到信号量技术变得大于0为止--如果另一个线程释放该信号量,就会发生这样的事情。 喜好两计数绝不会为负。在使用信号量时,你把信号量技术初始化为某个非负值,表示你拥有的资源的数量。
 
互斥体假定获取他的线程也将是释放他的线程。而信号量却相反,通常由一个线程获取,有另一个线程释放。正式这种独特的特征使得你能够如此有效的使用信号量。
 
我们将在一次实现生产者/消费者问题的一个解决方案,这一次使用计数信号量。我们把消费者持有的内建ACE_Message_Queue用作生产者和消费者之间的共享数据缓冲区。我们用信号量来控制任一时刻消息列队所能容纳的消息的最大数目。 换句话话说,我们实现了一种高水位(high-water-mark)机制;消息列队已经内建了这一功能;我们实际上是为了演示的目的而已一种低效的方式重新实现它。 为了让事情有趣一点,消费者任务拥有多个线程。
 
Producer把它生产出的ACE_Mess_Block放入消费者任务的消息列队中。每个块都有一个整型标识符,作为仅有的有效内容。生产者完成生产之后,发送一条挂断消息给消费者,使其关闭。
 
在生产任何数据项之前,生产者必须获取生产者信号量 psema_,他表示的是消费者的消息队列的最大容量(即高水位标)。在一开始,psema_的初始计数值被设置成高水位标的值。不能再在消费者的列队中放入更多元素了:
class Producer:public ACE_Task_Base
{
public:
enum{MAX_PROD=128};
Producer(ACE_Semaphore& psema,ACE_Semaphore&csema,Consumer &consumer)
:psema_(psema),csema_(csema),consumer_(consumer)
{}
 
int svc(void)
{
  for (int i=0;i<=MAX_PROD;i++)
     produce_item(i);
hang_up();
return 0;
}
 
void produce_item(int item)
{
psema_.acquire();
ACE_Message_Block *mb = new ACE_Message_Block(sizeof(int),
                          ACE_Message_Block::MB_DATA);
mb->wr_ptr(sizof(int));
this->consumer_.putq(mb);
 
ACE_DEBUG((LM_DEBUG,ACE_TEXT("(%t) Produced %d/n").item));
csema_release();
}
 
void hang_up()
{
psema_.acquire();
ACE_Message_Block *mb=
    new ACE_Message_Block(0,ACE_Message_Block::MB_HANGUP);
this->consumer_putq(mb);
csema_release():
}
 
private:
ACE_Semaphore& psema_;
ACE_Semaphore& csema_;
Consumer& consumer_;
}
 
另一方面,csema_信号量在意开哦是被初始化为0;生产者每生产出一个新的元素,都会调用csema_release() 使用这个值增一。如果有消费者线程阻塞在csema_变量的acquire()调用中,生产者没调用一次release(),就有有一个消费者线程苏醒过来,继而消费新生产的元素。
 
一旦解除阻塞,消费者线程就会消费队列中的元素,然后条用生产者信号量 psema_ 的release()方法,因为在消费之后,共享的消息列队中空除了一个位置。这会使 psema_计数增一,从而允许生产者继续执行,用完队列中的自由空间:
 
class Consumer : public ACE_Task<ACE_MT_SYNCH>
{
public:
emum { N_THREADS =5};
Consumer (ACE_Semaphore&psema,ACE_Semaphore& csema)
:psema_(psema),csema_(csema),exit_condition_(0)
{}
int svc(void)
{
while(!is_closed())
  consume_item();
return 0;
}
 
void consume_item()
{
csema_.acquire();
if(!is_closed())
{ACE_Message_Block *mb;
this->getq(mb);
if(mb->msg_type()== ACE_Message_block::MB_HANGUP)
shutdown();
mb-?release();
return;
}
else
{ACE_DEBUG((LM_DEBUG,
            ACE_TEXT("(%t) Consumed %d/n"),
            *((int*) mb->rd_ptr())));
 mb->release();
}
psema_release();
}
}
void shutdown(void)
{
exit_condition_=1;
this->msg_queue()->deactivate();
csema_.release(N_THREADS);
}
 
int is_closed(void)
{
return exit_condition_;
}
 
private:
ACE_Semaphore$ psema_;
ACE_Semaphopre& csema_;
int exit_condition_;
};
 
消费者任务的关闭有一点复杂,以为其中有多个线程在运行。因为生产者之发送一条挂断消息给消费者任务,只有一个线程会收到发哦这条消息其他线程则会阻塞,或是因为等待消息到达列队,或是因为在消费者信号量上等待。因此,收到的挂断消息的消费者线程必须把任务的状态标记为已关闭,然后唤醒其他所有线程,让它们注意到任务已关闭并退出。消费者的shutdown()方法是这样做的:首先把exit_condition_设成真,然后调用消息列队的deactivate(),唤醒其它的所有线程,然后让信号量计数减去消费者线程的数目,从而释放在信号量上等待的所有线程:
int ACE_TMAIN(int,ACE_TCHAR *[])
{
ACE_Semaphore psem(5);
ACE_Semaphore csem(0);
 
Consumer consumer(psem,csem);
Producer producer (psem,csem,consumer);
 
producer.activate();
consumer.activate(THR_NES_LWP | THR_JOINABLE,Consumer::N_THREADS);
 
producer.wait();
consumer.wait();
 
return 0;
}
除了两个信号量psem和csem的初始化,这里的代码咋很大程度上是公式化代码。重申一次,psem被初始化为列队中能容带的元素最大数目5,表明生产者可以生产到列队满为止。
 
另一方面,csem被初始化为0,表明在生产者调用csem的release()之前,消费者完全不能进行消费。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值