2014-01-11 3 views
1

Я редко думал о том, что происходит между двумя последовательными выражениями, между вызовом функции и выполнением ее первого выражения или между вызовом конструктора и выполнением его инициализатор. Тогда я начал читать о параллельности ...Порядок блокировки std :: mutex

1.) В течение двух последовательных вызовов конструктора std::thread «s с тем же отзывной (например, функции, функтора, лямбда), тело которого начинается с инициализации std::lock_guard с тем же объектом std::mutex , гарантирует ли стандарт, что поток, соответствующий первому вызову конструктора thread, сначала выполняет защищенный от блокировки код?

2.) Если стандарт не дает гарантии, то есть ли теоретическая или практическая возможность, что поток, соответствующий второму вызову конструктора thread, выполняет сначала защищенный код? (Например, тяжелая нагрузка системы во время выполнения инициализатора или органа первого вызова конструктора thread)

Вот глобальный std::mutex объекта m и глобальный unsignednum инициализируется 1. Нет ничего, кроме пробела между функцией foo 's открывающая скобка тела { и std::lock_guard. В main есть два std::thread s t1 и t2. t1 сначала вызывает конструктор потока. t2 вызывает второй конструктор потока. Каждый поток создается с указателем на foo. t1 звонки foo с unsigned аргумент 1. t2 звонки foo с unsigned аргумент 2. В зависимости от того, какая нить блокирует сначала mutex, значение num будет либо 4, либо 3 после того, как оба потока выполнили защищенный от блокировки код. num будет равно 4 если t1 бьет t2 до замка. В противном случае num будет равно 3. Я провел 100 000 испытаний этого путем циклирования и сброса num до 1 в конце каждого цикла. (Насколько я знаю, результаты не имеют и не должны зависеть от того, какой поток является join() ред первым.)

#include <thread> 
#include <mutex> 
#include <iostream> 

std::mutex m; 
unsigned short num = 1; 

void foo(unsigned short par) { 
    std::lock_guard<std::mutex> guard(m); 
    if (1 == num) 
     num += par; 
    else 
     num *= par; 
} 

int main() { 
    unsigned count = 0; 
    for (unsigned i = 0; i < 100000; ++i) { 
     std::thread t1(foo, 1); 
     std::thread t2(foo, 2); 
     t1.join(); 
     t2.join(); 
     if (4 == num) { 
      ++count; 
     } 
     num = 1; 
    } 
    std::cout << count << std::endl; 
} 

В конце концов, count равна 100000, так получается t1 выигрывает гонку каждый время. Но эти испытания ничего не доказывают.

3.) Существует ли стандартный мандат «сначала для вызова thread« конструктор »всегда подразумевает« сначала вызов вызываемого, переданного в конструктор thread »?

4.) Предусмотрен ли стандартный мандат «сначала для вызова вызываемого, переданного в конструктор thread», всегда означает «сначала заблокировать mutex»; если в теле вызываемого объекта отсутствует код, зависящий от параметра (ов), переданного вызываемому до строки с инициализацией std::lock_guard? (Также исключаю локальную static переменной любой вызываемого, как и счетчик числа раз называется, который может быть использован намеренно задерживать определенные вызовы.)

+2

Нет, да, непонятно, нет. –

ответ

3
  1. Нет, стандарт не гарантирует, что первый поток получает блокировка первый. В принципе, если вам нужно навязывать и заказывать между потоками, вам необходимо синхронизировать между этими потоками.Даже если первый поток получает вызов функции блокировки мьютекса, второй поток может сначала получить блокировку.
  2. Абсолютно. Например, в момент появления нитей может быть только одно ядро, доступное вашему приложению, и если нерестящий поток решает после того, как второй поток порождается, чтобы ждать чего-то, расписание может решить обработать последний поток, который является вторая нить. Даже если имеется много ядер, есть много причин, по которым второй поток быстрее.
  3. Нет, зачем? Первый шаг - создать поток и продолжить. К моменту первого вызова объекта функции второй поток может быть запущен и вызвать его функциональный объект.
  4. Нет. Между потоками нет гарантий поручения, если вы явно не навязываете их сами, поскольку они победят цель параллелизма.
Смежные вопросы