Как работает фьютекс в этом случае?

У меня есть пример кода фьютекса. Но я не мог понять поток кода....

#include <stdio.h>
#include <pthread.h>
#include <linux/futex.h>
#include <syscall.h>
#include <unistd.h>

#define NUM 50

int futex_addr;

int futex_wait(void* addr, int val1){
  return syscall(SYS_futex,&futex_addr,val1, NULL, NULL, 0);
}
int futex_wake(void* addr, int n){
  return syscall(SYS_futex, addr, FUTEX_WAKE, n, NULL, NULL, 0);
}

void* thread_f(void* par){
        int id = (int) par;

    /*go to sleep*/
    futex_addr = 0;
    futex_wait(&futex_addr,0);

        printf("Thread %d starting to work!\n",id);
        return NULL;
}

int main(){
        pthread_t threads[NUM];
        int i;

        for (i=0;i<NUM;i++){
                pthread_create(&threads[i],NULL,thread_f,(void *)i);
        }

        printf("Everyone wait...\n");
        sleep(1);
        printf("Now go!\n");
    /*wake threads*/
    futex_wake(&futex_addr,50);

    /*give the threads time to complete their tasks*/
        sleep(1);


    printf("Main is quitting...\n");
        return 0;
}

вывод выглядит следующим образом:

Everyone wait...
Now go!
Thread 0 starting to work!
Thread 1 starting to work!
Thread 2 starting to work!
Thread 3 starting to work!
Thread 4 starting to work!
Thread 5 starting to work!
Thread 6 starting to work!
Thread 7 starting to work
Thread 8 starting to work!
Thread 9 starting to work!
.
.
Main is quitting

Как на самом деле ведет себя этот код??

что такое триггер для функций thread_f ??

Как здесь работает ожидание и пробуждение??


person Prashanth Cm    schedule 30.06.2014    source источник
comment
Не используйте фьютекс; использовать pthreads (который построен над фьютексами)   -  person Basile Starynkevitch    schedule 30.06.2014
comment
да.. но это всего лишь пример кода, который я получил... но я хочу понять, как выполняется код....!!   -  person Prashanth Cm    schedule 30.06.2014
comment
Затем прочитайте futex(7) и поймите, что это всего лишь для разработчиков библиотек потоков (например, разработчиков gnu libc + pthreads)   -  person Basile Starynkevitch    schedule 30.06.2014


Ответы (1)


  1. Вы создаете 50 потоков и усыпляете основной поток.
  2. В каждом потоке вы устанавливаете значение futex_addr равным нулю (избыточно).
  3. Вы вызываете futex_wait с адресом этого значения и нулевым параметром значения. Это означает "блокировать, если значение, на которое я указываю, (по-прежнему) действительно равно нулю".
  4. sys_futex проверяет, что значение в &futex_addr действительно равно нулю, что является условием блокировки вашего потока (это важно для корректной работы системного вызова, иначе futex_wake пришлось бы блокировать так же, как NtReleaseKeyedEvent под Windows). Конечно, значение равно нулю, это все, что любой поток когда-либо писал в него, поэтому ваш поток блокируется.
  5. В конце концов основной поток возвращается из sleep и вызывает futex_wake с параметром 50, что означает "разбудить (до) 50 потоков, ожидающих &futex_addr". Так что все ваши 50 тредов просыпаются одним большим грохочущим стадом.
  6. Каждый поток записывает сообщение в stdout (без синхронизации, поэтому вы можете увидеть искаженный вывод) и завершает работу.
  7. Основной поток также завершается без присоединения к потокам или синхронизации, но из-за второго вызова sleep есть вероятность, что он будет «работать нормально» без каких-либо плохих вещей (не то чтобы это было хорошо писать такой код! ).

Обратите внимание, что этот метод пробуждения N потоков работает, но не рекомендуется (как и использование futex в первую очередь тоже не рекомендуется). Обычно вы хотите разбудить ровно один поток (используйте 1) или все потоки (используйте INT_MAX).

person Damon    schedule 30.06.2014
comment
Я имею в виду, что сначала все подождите... распечатывается позже Thread %d начинает работать!\n распечатывается. Удивительно, но вызов thread_f выполняется до того, как все подождут... печать.... - person Prashanth Cm; 01.07.2014
comment
Триггером для thread_f является pthread_create, который зависит от а) запланированного основного потока б) дюжины запущенных потоков, конкурирующих с основным потоком за процессорное время в) случайных вещей и г) несинхронизированного использования функций stdio, что может дать непредсказуемый выход. Не указано, какой поток запланирован первым после clone (что и происходит внутри pthread_create). Скорее всего, они запустятся в том порядке, в котором их создал основной поток, но может произойти что-то другое. Аналогично верно для printf и write (который вызывается внутри). Они не атомарны. - person Damon; 01.07.2014
comment
Таким образом, результат, который вы видите, не очень четко определен. Вы можете видеть вывод потока 4. Все ждут до того, как поток 1 выведет Starting, и вы даже можете увидеть вывод потока 6 первым, несмотря на то, что поток 1 запланирован первым (и снова прерван по какой-то причине). Или вы могли видеть полуполные сообщения, или полный мусор, даже это возможно. - person Damon; 01.07.2014