Выполнение без переключения между потоками (c ++ 11)

Я новичок в C ++ 11 многопоточности. Я работаю с маленькими кодами и столкнулся с этой проблемой. Вот код:

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

std::mutex print_mutex;

void function1()
{
std::cout << "Thread1 started" << std::endl;

while (true)
{
std::unique_lock<std::mutex> lock(print_mutex);
for (size_t i = 0; i<= 1000000000; i++)
continue;
std::cout << "This is function1" << std::endl;
lock.unlock();
}
}

void function2()
{
std::cout << "Thread2 started" << std::endl;
while (true)
{
std::unique_lock<std::mutex> lock(print_mutex);
for (size_t i = 0; i <= 1000000000; i++)
continue;
std::cout << "This is function2" << std::endl;
lock.unlock();
}
}

int main()
{
std::thread t1(function1);
std::thread t2(function2);

t1.join();
t2.join();

return 0;
}

Я написал код с интуицией ожидания следующего вывода:

Тема 1 запущена
Тема 2 запущена

Это
function1
Это функция2
Это функция1
. .
.
.

Но показанный результат выглядит следующим образом:

Тема 1 запущена
Тема 2 запущена

Это функция1

Это функция1
Это
function1
.
.
.

Куда я иду не так?

2

Решение

Оба ваших потока делают следующие шаги:

  • Замок
  • Длинный пустой цикл
  • Распечатать
  • отпереть
  • Замок
  • Длинный пустой цикл
  • (и так далее)

Практически, вы не оставили в любой момент для переключения контекста есть блокировка сразу после разблокировки. Решение: поменяйте местами шаги «lock» и «long empty loop», чтобы заблокировать только шаг «print», планировщик может переключиться на другой поток во время «long empty loop».

Добро пожаловать в темы!

Редактировать: Pro Tipp: отладка многопоточных программ сложна. Но иногда стоит вставить простой printf () для обозначения блокировок и разблокировок (правильный порядок: lock, затем printf и printf, а затем разблокировать), даже когда программа кажется корректной. В этом случае вы могли видеть нулевой разрыв между разблокировкой-блокировкой.

2

Другие решения

Разблокировка мьютекса не гарантирует, что другой поток, ожидающий блокировки того же мьютекса, немедленно получит блокировку.

Это только гарантирует, что другой поток будет ПЫТАТЬСЯ приобрести замок.

В этом случае после того, как вы разблокируете мьютекс в одном потоке, тот же поток немедленно попытается заблокировать его снова. Даже если другой поток терпеливо ждал мьютекса, это не гарантирует, что другой поток выиграет в этот раз. Тот же поток, который только что заблокировал его, может немедленно заблокировать его снова.

Сегодня вы видите, что одна и та же нить всегда побеждает в гонке блокировки. Завтра вы можете обнаружить, что это всегда другой поток, который делает. У вас нет никаких гарантий, какой поток получит мьютекс, когда более одного потока будет следовать за одним и тем же мьютексом в одно и то же время. Победитель зависит от вашего процессора и другой аппаратной архитектуры, загруженности системы, времени и многих других факторов.

2

Это верный результат, ваш код не пытается каким-либо образом управлять порядком выполнения, если все потоки выполняются в какой-то момент и проблем нет, и это законный результат.

Это может произойти, даже если вы переключили порядок цикла и блокировки (посмотреть здесь), потому что, опять же, вы не написали ничего, что пыталось бы управлять им, например, условные переменные или просто некоторые глупый atomic_bool(это глупое решение, просто чтобы продемонстрировать, как вы можете сделать его чередующимся и быть уверенным, что оно будет) Булево, чтобы чередовать прогоны.

0
По вопросам рекламы [email protected]