c ++ Почему бы мне не разблокировать мьютекс из другого потока - PullRequest
0 голосов
/ 28 мая 2020

Почему бы мне не разблокировать мьютекс из другого потока? В стандарте C ++ сказано довольно четко: если мьютекс в настоящее время не заблокирован вызывающим потоком, это вызывает неопределенное поведение. Но, насколько я могу судить, на Linux (Fedora 31 с G CC) все работает как положено. Я серьезно пробовал все, но не мог заставить себя вести себя странно. Все, о чем я прошу, - это пример, где что-то, буквально все, зависит от разблокировки мьютекса из другого потока. :

std::mutex* testEvent;

int main()
{
    testEvent = new std::mutex[1000];

    for(uint32_t i = 0; i < 1000; ++i) testEvent[i].lock();

    std::thread threads[2000];

    auto lock = [](uint32_t index) ->void { testEvent[index].lock(); assert(!testEvent[index].try_lock()); };
    auto unlock = [](uint32_t index) ->void { testEvent[index].unlock(); };

    for(uint32_t j = 0; j < 1000; ++j)
    {
        for(uint32_t i = 0; i < 1000; ++i)
        {
            threads[i]      = std::thread(lock,i);
            threads[i+1000] = std::thread(unlock,i);
        }
        for(uint32_t i = 0; i < 2000; ++i)
        {
            threads[i].join();
        }
        std::cout << j << std::endl;
    }

    delete[] testEvent;
}

Ответы [ 3 ]

3 голосов
/ 28 мая 2020

Как вы уже сказали, это УБ. UB означает, что может работать. Или не. Или случайным образом переключайтесь между работой и заставкой вашего компьютера петь колыбельную. (См. Также «назальные демоны».)

Вот лишь несколько способов сломать вашу программу в Fedora 31 с помощью G CC на x86-64:

  1. Компилировать с -fsanitize=thread. Теперь он будет каждый раз сканировать sh, что по-прежнему является допустимой реализацией C ++, потому что UB.
  2. Run unter helgrind (valgrind --tool=helgrind ./a.out). Он будет sh каждый раз взламывать - по-прежнему допустимый способ разместить программу на C ++, потому что UB.
  3. Реализация libstdc ++ / glibc / pthread в целевой системе по умолчанию переключается с использования «быстрых» мьютексов на «проверка ошибок» или «рекурсивные» мьютексы (https://manpages.debian.org/jessie/glibc-doc/pthread_mutex_init.3.en.html). Обратите внимание, что это, вероятно, возможно способом, совместимым с ABI с вашей программой, а это означает, что ее даже не нужно перекомпилировать, чтобы она внезапно перестала работать.

При этом используют платформу, на которой мьютекс C ++ сводится к реализованному на фьютексе «быстрому» мьютексу pthread, это не сработает случайно. Просто не гарантируется, что вы продолжите работать в течение любого времени или в любых обстоятельствах, которые действительно проверяют, правильно ли вы поступаете.

0 голосов
/ 28 мая 2020

Поскольку мьютекс является мьютексом, а поведение undefined - это поведение undefined.

Если вам нужен такой объект, вам понадобится семафор .

C ++ 20 имеет семафоры: std::binary_semaphore, std::counting_semaphore. См. cppreference .

Перед этим вы должны использовать семафоры c, специфичные для платформы. Или, может быть, накатите свой собственный поверх имеющихся у вас предметов.

0 голосов
/ 28 мая 2020

Мне действительно интересно, зачем вам вообще это нужно;)

Обычно вам нужно что-то вроде

lock();
do_critical_task();
unlock();

(В C ++ блокировка / разблокировка часто скрывается с помощью std::lock_guard или подобного.)
Предположим, что один поток (скажем, поток A) вызвал этот код и находится внутри критической задачи, т.е. он также удерживает блокировку. Затем, если вы разблокируете тот же мьютекс из другого потока, любой поток, кроме A, также может войти в критическую секцию одновременно.

Основная цель мьютексов - иметь взаимное исключение (отсюда их название), поэтому все, что вы do - это стереть назначение мьютекса;)

Тем не менее: вы всегда должны верить стандарту. Только если что-то работает в определенной системе, это не значит, что она портативна. Плюс: особенно в параллельном контексте, многое может сработать тысячу раз, но затем выйдет из строя в 1001-й раз из-за условий гонки. В математике вашу попытку можно было бы сравнить с «доказательством на примере».

...