关于使用多个信号量的同步

时间:2012-10-29 02:10:26

标签: c synchronization pthreads semaphore

您好我正在进行有关使用具有多信号量的POSIX线程的任务。分配的简要说明是:有4种不同的数据包(字符/视频/音频/图像),每个数据包由不同的线程承载,我们也有共享缓冲区。最大线程可以在系统上工作,将由用户作为输入维护。例如;如果用户输入10,则可以创建最多10个线程,以在给定时间内通过缓冲区传输数据包。现在令我困惑的部分是,这个缓冲区可以立即包含有限的数据包。 (例如,它可以包含最多10个char数据包和20个视频数据包等),因此我们必须为每种数据类型提供不同的信号量。问题我知道如何用信号量控制缓冲区大小这很简单,但不能设置使用数据包信号量的正确想法。即使我尝试了一些不同的方法,我总是遇到死锁错误。这是我的伪代码,可以更清楚地了解我的程序。

define struct packege
define semaphore list

main

initialize variables and semaphores

while threadCounter is less than MaxThreadNumber

switch(random)
case 0: create a character package
    create a thread to insert the package in buffer
case 1: create a video package
    create a thread to insert the package in buffer
case 2: create an image package
    create a thread to insert the package in buffer
case 3: create an audio package
    create a thread to insert the package in buffer

increment  threadCounter by one
end of while

create only one thread which will make the dequeue operation
end of main

producer function

for i->0 to size_of_package
    sem_wait(empty_buffer) // decrement empty_buffer semaphore by size of package

    lock_mutex
        insert item into queueu
        decrement counter of the buffer by size of package
    unlock_mutex

for i->0 to size_of_package
    sem_post(full_buffer) // increment full_buffer semaphore by size of package

end of producer function

consumer function

while TRUE // Loops forever

    lock_mutex

        if queue is not empty
            dequeue

        increment counter of the buffer size of package

    unlock_mutex

for i->0 to size_of_package // The reason why i making the sem_wait operation here is i cant make the dequeue in outer region of mutex.
    sem_wait(full_buffer)
for i->0 to size_of_package
    sem_post(empty_buffer)
end of consumer function

使用此实现程序正常工作。但我不能正确使用信号量,它属于包的线程。我可以倾听每一个建议,并会对每个答案表示赞赏。

2 个答案:

答案 0 :(得分:1)

这不是信号量的使用方式。缓冲区的控制变量/结构应该计算缓冲区中包含的消息数量以及类型。互斥锁保护缓冲区及其控制变量/结构免受不同线程的并发访问。信号量(如果使用的话)只是向缓冲区发送缓冲区的状态信号,并且与数据包的大小没有关联;它肯定不会增加数据包的大小!

建议您使用pthread条件变量而不是信号量。它们与pthread互斥锁一起使用,以保证线程之间的无竞争信令。生产者循环执行此操作:

  • 锁定互斥锁,
  • 修改缓冲区等以添加新数据包,
  • 表示条件变量,
  • 解锁互斥锁。

消费者循环执行此操作:

  • 锁定互斥锁,
  • 处理所有缓冲的数据,
  • 等待条件变量。

阅读pthread_cond_initpthread_cond_signalpthread_cond_wait

答案 1 :(得分:1)

由于它是一个赋值,你可能不需要读取和写入真正的数据包数据,而只是模拟它们的处理。

在这种情况下,问题归结为如何在生产者线程达到可以在缓冲区中写入的数据包限制时有效地阻止生产者线程。目前,据我所知,您正在使用信号量来计算缓冲区中写入的数据包的各个元素。

想象一下,您在缓冲区中的写入是原子的,并且您只想计算数据包,而不是数据包元素。每次生产者写入数据包时,它必须使用适当的信号量向消费者发送信号,并且每次消费者读取数据包时,它必须将信号发送给适当的生产者。

让我强调其他几点:

  • 信号量的重要特性是它会在达到零时阻塞。例如,如果其初始值为10,则在连续10次sem_get之后,第11个将阻塞。
  • 您有4种类型的数据包,每种数据包的数量都可以在缓冲区中写入。

正如我所说,制作人必须发信号通知它写了一个数据包,但一旦达到阈值就必须停止。为实现这一目标,您可以在每次发布新数据包时使用sem_get获取信号量。每次读取数据包时,消费者都会执行sem_post,这与您使用单个信号量版本所做的相反。但是,由于您希望生产者停在阈值处,因此初始化信号量的容量为N - 1,N为阈值。请注意,在缓冲区中写入新数据包后,必须发出新数据包的信号,否则消费者可能会阻止缓冲区。

producer<type> function

  write_packet()  // put the packet in the buffer
  sem_wait(type)    // signal a new packet is available 
  // (if there's not enough space for another packet, the producer will block here) 

end producer<type> function

consumer function

  while TRUE // Loops forever

      switch packet_available() // look if there's a new packet available
       case video:
         read_packet<video>()
         sem_post(video)
       (...)
       default: // no packet available, just wait a little
          sleep()
      end if
  end while

您仍需要定义packet_readpacket_writepacket_available函数,可能使用互斥锁来限制对缓冲区的访问。