linux下信号量semaphore的应用

时间:2021-11-26 02:16:12

生产者线程用于往链表里添加节点,数个工作线程从链表取出节点并处理。对于一般的mutex_lock,mutex_unlock方式,如果这一段时间没有工作,那么工作线程将会不停的调用lock,unlock操作。而这样的操作毫无疑义。

在这里系统给我们提供了另外一种同步机制,信号灯,Semaphore。

信号灯其实就是一个计数器,也是一个整数。每一次调用wait操作将会使semaphore值减一,而如果semaphore值已经为0,则wait操作将会阻塞。每一次调用post操作将会使semaphore值加一。将这些操作用到上面的问题中。工作线程每一次调用wait操作,如果此时链表中没有节点,则工作线程将会阻塞,直到链表中有节点。生产者线程在每次往链表中添加节点后调用post操作,信号灯值会加一。这样阻塞的工作线程就会停止阻塞,继续往下执行。

信号灯的类型为sem_t。在声明后必须调用sem_init()。需要传递两个参数,第一个参数就是你之前声明的sem_t变量,第二个必须为0。当你不再需要信号灯时,你必须调用sem_destroy()来释放资源。

等待信号灯的操作为sem_wait()。投递一个信号的操作为sem_post()。和互斥量一样,等待信号灯也有一个非阻塞的操作,sem_trywait()。该操作在没有信号灯的时候返回EAGAIN。

下面是一个结合了互斥量和信号灯的例子:

  1. #include <malloc.h>  
  2. #include <pthread.h>  
  3. #include <semaphore.h>  
  4. struct job {  
  5. /* Link field for linked list. */  
  6. struct job* next;  
  7. /* Other fields describing work to be done... */  
  8. };  
  9. /* A linked list of pending jobs. */  
  10. struct job* job_queue;  
  11. /* A mutex protecting job_queue. */  
  12. pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;  
  13. /* A semaphore counting the number of jobs in the queue. */  
  14. sem_t job_queue_count;  
  15. /* Perform one-time initialization of the job queue. */  
  16. void initialize_job_queue ()  
  17. {  
  18. /* The queue is initially empty. */  
  19. job_queue = NULL;  
  20. /* Initialize the semaphore which counts jobs in the queue. Its 
  21. initial value should be zero. */  
  22. sem_init (&job_queue_count, 0, 0);  
  23. }  
  24. /* Process queued jobs until the queue is empty. */  
  25. void* thread_function (void* arg)  
  26. {  
  27. while (1) {  
  28. struct job* next_job;  
  29. /* Wait on the job queue semaphore. If its value is positive, 
  30. indicating that the queue is not empty, decrement the count by 
  31. 1. If the queue is empty, block until a new job is enqueued. */  
  32. sem_wait (&job_queue_count);  
  33. /* Lock the mutex on the job queue. */  
  34. pthread_mutex_lock (&job_queue_mutex);  
  35. /* Because of the semaphore, we know the queue is not empty. Get 
  36. the next available job. */  
  37. next_job = job_queue;  
  38. /* Remove this job from the list. */  
  39. job_queue = job_queue->next;  
  40. /* Unlock the mutex on the job queue because we’re done with the 
  41. queue for now. */  
  42. pthread_mutex_unlock (&job_queue_mutex);  
  43. /* Carry out the work. */  
  44. process_job (next_job);  
  45. /* Clean up. */  
  46. free (next_job);  
  47. }  
  48. return NULL;  
  49. }  
  50. /* Add a new job to the front of the job queue. */  
  51. void enqueue_job (/* Pass job-specific data here... */)  
  52. {  
  53. struct job* new_job;  
  54. /* Allocate a new job object. */  
  55. new_job = (struct job*) malloc (sizeof (struct job));  
  56. /* Set the other fields of the job struct here... */  
  57. /* Lock the mutex on the job queue before accessing it. */  
  58. pthread_mutex_lock (&job_queue_mutex);  
  59. /* Place the new job at the head of the queue. */  
  60. new_job->next = job_queue;  
  61. job_queue = new_job;  
  62. /* Post to the semaphore to indicate that another job is available. If 
  63. threads are blocked, waiting on the semaphore, one will become 
  64. unblocked so it can process the job. */  
  65. sem_post (&job_queue_count);  
  66. /* Unlock the job queue mutex. */  
  67. pthread_mutex_unlock (&job_queue_mutex);