The sem_getvalue function returns the current value of the semaphore counter if there are no threads waiting. If threads are waiting, sem_getvalue returns a negative number. The absolute value of that number tells how many threads are waiting on the semaphore. Keep in mind that the value it returns may already be incorrect — it can change at any time due to the action of some other thread.

The best use for sem_getvalue is as a way to wake multiple waiters, somewhat like a condition variable broadcast. Without sem_getvalue, you have no way of knowing how many threads might be blocked on a semaphore. To 'broadcast' a semaphore, you could call sem_getvalue and sem_post in a loop until sem_getvalue reports that there are no more waiters.

But remember that other threads can call sem_post during this loop, and there is no synchronization between the various concurrent calls to sem_post and sem_getvalue. You can easily end up issuing one or more extra calls to sem_post, which will cause the next thread that calls sem_wait to find a value greater than 0, and return immediately without blocking.

The program below, semaphore_signal.c, uses a semaphore to awaken threads from within a POSIX signal- catching function. Notice that the sem_init call sets the initial value to 0 so that each thread calling sem_wait will block. The main program then requests an interval timer, with a POSIX signal-catching function that will wake one waiting thread by calling sem_post. Each occurrence of the POSIX timer signal will awaken one waiting thread. The program will exit when each thread has been awakened five times.

32-35 Notice the code to check for EINTR return status from the sem_wait call. The POSIX timer signal in this program will always occur while one or more threads are blocked in sem_wait. When a signal occurs for a process (such as a timer signal), the system may deliver that signal within the context of any thread within the process. Likely 'victims' include threads that the kernel knows to be waiting, for example, on a semaphore. So there is a fairly good chance that the sem_wait thread will be chosen, at least sometimes. If that occurs, the call to sem_wait will return with EINTR. The thread must then retry the call. Treating an EINTR return as 'success' would make it appear that two threads had been awakened by each call to sem_post: the thread that was interrupted, and the thread that was awakened by the sem_post call.

¦ semaphore_signal.c

1 #include <sys/types.h>

2 #include <unistd.h>

3 #include <pthread.h>

4 #include <semaphore.h>

5 #include <signal.h>

6 #include <time.h>

7 #include 'errors.h'

8

9 sem_t semaphore;

10

11 /*

12 * Signal-catching function.

13 */

14 void signal_catcher (int sig)

15 {

16  if (sem_post (&semaphore) == -1)

17  errno_abort ('Post semaphore');

18 }

19

20 /*

21 * Thread start routine which waits on the semaphore.

22 */

23 void *sem_waiter (void *arg)

24 {

25 int number = (int)arg;

26 int counter;

27

28 /*

29 * Each thread waits 5 times.

30 */

31 for (counter = 1; counter <= 5; counter++) {

32 while (sem_wait (&semaphore) == -1) {

33  if (errno != EINTR)

34  errno_abort ('Wait on semaphore');

35 }

36 printf ('%d waking (%d)... ', number, counter);

37 }

38 return NULL;

39 }

40

41 int main (int argc, char *argv[])

42 {

43 int thread_count, status;

44 struct sigevent sig_event;

45 struct sigaction sig_action;

46 sigset_t sig_mask;

47 timer_t timer_id;

48 struct itimerspec timer_val;

49 pthread_t sem_waiters[5];

50

51 #if !defined(_POSIX_SEMAPHORES) || !defined(_POSIX_TIMERS)

52 #if !defined(_POSIX_SEMAPHORES)

53 printf ('This system does not support POSIX semaphores ');

54 # endif

55 #if !defined(_POSIX_TIMERS)

56 printf ('This system does not support POSIX timers ');

57 #endif

58 return -1;

59 #else

60 sem_init (&semaphore, 0, 0);

61

62 /*

63 * Create 5 threads to wait on a semaphore.

64 */

65 for (thread_count = 0; thread_count < 5; thread_count++) {

66  status = pthread_create (

67  &sem_waiters[thread_count], NULL,

68  sem_waiter, (void*)thread_count);

69 if (status != 0)

70  err_abort (status, 'Create thread');

71 }

72

73 /*

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату