Я новичок в 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
.
.
.
Куда я иду не так?
Оба ваших потока делают следующие шаги:
Практически, вы не оставили в любой момент для переключения контекста есть блокировка сразу после разблокировки. Решение: поменяйте местами шаги «lock» и «long empty loop», чтобы заблокировать только шаг «print», планировщик может переключиться на другой поток во время «long empty loop».
Добро пожаловать в темы!
Редактировать: Pro Tipp: отладка многопоточных программ сложна. Но иногда стоит вставить простой printf () для обозначения блокировок и разблокировок (правильный порядок: lock, затем printf и printf, а затем разблокировать), даже когда программа кажется корректной. В этом случае вы могли видеть нулевой разрыв между разблокировкой-блокировкой.
Разблокировка мьютекса не гарантирует, что другой поток, ожидающий блокировки того же мьютекса, немедленно получит блокировку.
Это только гарантирует, что другой поток будет ПЫТАТЬСЯ приобрести замок.
В этом случае после того, как вы разблокируете мьютекс в одном потоке, тот же поток немедленно попытается заблокировать его снова. Даже если другой поток терпеливо ждал мьютекса, это не гарантирует, что другой поток выиграет в этот раз. Тот же поток, который только что заблокировал его, может немедленно заблокировать его снова.
Сегодня вы видите, что одна и та же нить всегда побеждает в гонке блокировки. Завтра вы можете обнаружить, что это всегда другой поток, который делает. У вас нет никаких гарантий, какой поток получит мьютекс, когда более одного потока будет следовать за одним и тем же мьютексом в одно и то же время. Победитель зависит от вашего процессора и другой аппаратной архитектуры, загруженности системы, времени и многих других факторов.
Это верный результат, ваш код не пытается каким-либо образом управлять порядком выполнения, если все потоки выполняются в какой-то момент и проблем нет, и это законный результат.
Это может произойти, даже если вы переключили порядок цикла и блокировки (посмотреть здесь), потому что, опять же, вы не написали ничего, что пыталось бы управлять им, например, условные переменные или просто некоторые глупый atomic_bool
(это глупое решение, просто чтобы продемонстрировать, как вы можете сделать его чередующимся и быть уверенным, что оно будет) Булево, чтобы чередовать прогоны.