Изучение мьютексов и потоков - вопрос относительно условий гонки - PullRequest
0 голосов
/ 06 мая 2020

Я немного учу себя параллельному программированию, особенно с использованием мьютексов и потоков в C ++. Я написал следующий небольшой пример:

#include <iostream>
#include <thread>
#include <mutex>
// #include <chrono>

std::mutex M1,M2;

void task_one () {
    std::cout << "AAAA!\n";
    M1.lock();
    // std::cout << "M1 locked in A\n";
    M2.lock();
    // std::cout << "M2 locked in A\n";
    std::cout << "BBBB!\n";
    M2.unlock();
    // std::cout << "M2 unlocked in A\n";
    M1.unlock();
    // std::cout << "M2 unlocked in A\n";
}

void task_two () {
    std::cout << "CCCC!\n";
    M2.lock();
    // std::cout << "M2 locked in B\n";
    M1.lock();
    // std::cout << "M1 locked in B\n";
    std::cout << "DDDD!\n";
    // M1.unlock();
    // std::cout << "M1 unlocked in B\n";
    M2.unlock();
    // std::cout << "M2 unlocked in B\n";
}

int main () {
    std::thread th1 (task_one);
    std::thread th2 (task_two);
    th1.join();
    th2.join();

    // th1.detach();
    // th2.detach();
    // std::chrono::milliseconds timespan(10);
    // std::this_thread::sleep_for(timespan);
    return 0;
}

Я ожидал, что этот код напечатает

AAAA!
CCCC!

, а затем заблокируется, когда task_one попытается получить блокировку на M2 (потому что task_two уже получит этот замок). Однако он печатает

AAAA!
BBBB!
CCCC!
DDDD!

Почему нет тупика? Кроме того, является ли это примером состояния гонки или этот код является поточно-ориентированным? Я думаю, что существует состояние гонки, потому что, если task_one может получить блокировку на M2 до того, как task_two сможет, тогда все будет выполнено (то есть task_one завершит sh, а затем позволит task_two начать) . Однако я запускал это несколько раз с теми же результатами. Кроме того, если мое словоблудие в отношении блокировок и потоков неверно, пожалуйста, поправьте меня.

1 Ответ

2 голосов
/ 06 мая 2020

Просто потому, что тупик может произойти (что действительно может произойти в опубликованном коде), не означает, что это всегда будет .

В вашем В этом случае task_one выполняется до завершения до того, как task_two вообще запускается.

Многопоточность выглядит так: скользко.

...