Разобраться в коде, где непосредственно делается вызов чтобы разбудить все потоки - C (СИ)
Формулировка задачи:
помогите разобраться в коде где непосредственно делается вызов чтобы разбудить все потоки? Какой вызов используется?
Есть один вызов lll_lock и два вызова lll_unlock, но при этом всё правильно работает. Почему?
Листинг программы
- /* Copyright (C) 2003-2015 Free Software Foundation, Inc.
- 2 This file is part of the GNU C Library.
- 3 Contributed by Martin Schwidefsky <removed@mail.ru>, 2003.
- 4
- 5 The GNU C Library is free software; you can redistribute it and/or
- 6 modify it under the terms of the GNU Lesser General Public
- 7 License as published by the Free Software Foundation; either
- 8 version 2.1 of the License, or (at your option) any later version.
- 9
- 10 The GNU C Library is distributed in the hope that it will be useful,
- 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
- 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- 13 Lesser General Public License for more details.
- 14
- 15 You should have received a copy of the GNU Lesser General Public
- 16 License along with the GNU C Library; if not, see
- 17 <http://www.gnu.org/licenses/>. */
- 18
- 19 #include <endian.h>
- 20 #include <errno.h>
- 21 #include <sysdep.h>
- 22 #include <lowlevellock.h>
- 23 #include <pthread.h>
- 24 #include <pthreadP.h>
- 25 #include <stap-probe.h>
- 26
- 27 #include <shlib-compat.h>
- 28 #include <kernel-features.h>
- 29
- 30
- 31 int
- 32 __pthread_cond_broadcast (cond)
- 33 pthread_cond_t *cond;
- 34 {
- 35 LIBC_PROBE (cond_broadcast, 1, cond);
- 36
- 37 int pshared = (cond->__data.__mutex == (void *) ~0l)
- 38 ? LLL_SHARED : LLL_PRIVATE;
- 39 /* Make sure we are alone. */
- 40 lll_lock (cond->__data.__lock, pshared);
- 41
- 42 /* Are there any waiters to be woken? */
- 43 if (cond->__data.__total_seq > cond->__data.__wakeup_seq)
- 44 {
- 45 /* Yes. Mark them all as woken. */
- 46 cond->__data.__wakeup_seq = cond->__data.__total_seq;
- 47 cond->__data.__woken_seq = cond->__data.__total_seq;
- 48 cond->__data.__futex = (unsigned int) cond->__data.__total_seq * 2;
- 49 int futex_val = cond->__data.__futex;
- 50 /* Signal that a broadcast happened. */
- 51 ++cond->__data.__broadcast_seq;
- 52
- 53 /* We are done. */
- 54 lll_unlock (cond->__data.__lock, pshared);
- 55
- 56 /* Wake everybody. */
- 57 pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex;
- 58
- 59 /* Do not use requeue for pshared condvars. */
- 60 if (mut == (void *) ~0l
- 61 || PTHREAD_MUTEX_PSHARED (mut) & PTHREAD_MUTEX_PSHARED_BIT)
- 62 goto wake_all;
- 63
- 64 #if (defined lll_futex_cmp_requeue_pi \
- 65 && defined __ASSUME_REQUEUE_PI)
- 66 if (USE_REQUEUE_PI (mut))
- 67 {
- 68 if (lll_futex_cmp_requeue_pi (&cond->__data.__futex, 1, INT_MAX,
- 69 &mut->__data.__lock, futex_val,
- 70 LLL_PRIVATE) == 0)
- 71 return 0;
- 72 }
- 73 else
- 74 #endif
- 75 /* lll_futex_requeue returns 0 for success and non-zero
- 76 for errors. */
- 77 if (!__builtin_expect (lll_futex_requeue (&cond->__data.__futex, 1,
- 78 INT_MAX, &mut->__data.__lock,
- 79 futex_val, LLL_PRIVATE), 0))
- 80 return 0;
- 81
- 82 wake_all:
- 83 lll_futex_wake (&cond->__data.__futex, INT_MAX, pshared);
- 84 return 0;
- 85 }
- 86
- 87 /* We are done. */
- 88 lll_unlock (cond->__data.__lock, pshared);
- 89
- 90 return 0;
- 91 }
- 92
- 93 versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
- 94 GLIBC_2_3_2);
Решение задачи: «Разобраться в коде, где непосредственно делается вызов чтобы разбудить все потоки»
textual
Листинг программы
- /* Wake everybody. */
- pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex;
- /* Do not use requeue for pshared condvars. */
- if (mut == (void *) ~0l
- || PTHREAD_MUTEX_PSHARED (mut) & PTHREAD_MUTEX_PSHARED_BIT)
- goto wake_all;
- /* ... */
- wake_all:
- lll_futex_wake (&cond->__data.__futex, INT_MAX, pshared);
Объяснение кода листинга программы
pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex;
- в этой строке кода происходит приведение типа указателя на объект типаpthread_mutex_t
к типуvoid*
с помощью оператораcast
. Это необходимо для того, чтобы привести указатель к типу, который ожидает функцияlll_futex_wake
.if (mut == (void *) ~0l || PTHREAD_MUTEX_PSHARED (mut) & PTHREAD_MUTEX_PSHARED_BIT)
- в этом блоке кода выполняется проверка условия. Если значение указателяmut
равно значению, которое возвращает оператор~0l
(что эквивалентноUINT_MAX
), или битPTHREAD_MUTEX_PSHARED
в значенииmut
установлен в1
, то управление передается операторуgoto wake_all
.goto wake_all;
- переход к операторуlll_futex_wake
с помощью оператораgoto
.lll_futex_wake (&cond->__data.__futex, INT_MAX, pshared);
- в этой строке кода происходит вызов функцииlll_futex_wake
, которая предназначена для пробуждения всех потоков, ожидающих на условной переменной. Аргументами функции являются адрес условной переменной, максимальное количество потоков, которые следует разбудить, и флаг, указывающий, является ли условная переменная общей.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д