C++, запуск двух функций в параллельном и совместном режиме
У меня есть два метода, которые я хочу выполнить параллельно, данные передаются по константной ссылке.
Как только один из методов завершил свою работу, другому нет необходимости продолжать, так как один из них может иметь длительное время выполнения в зависимости от входа и поэтому должен остановиться.
Я обнаружил, что могу выполнять два метода параллельно, запустив два потока, используя <thread>
заголовок, но мне пришлось ждать окончания обоих методов после их соединения.
Как я могу достичь этого типа параллельной обработки с таким совместным механизмом?
1 ответ
Я написал небольшой пример, чтобы показать, как это делается. Это не архивируется с join, как вы уже узнали. Вам нужно событие, о котором вы можете сообщить из потока, когда оно даст результат. Для этого вы должны использовать std::conditon_variable
, Пример показывает минимально возможное решение для вашей описанной проблемы. В примере, простой результат в.
Есть две ловушки, которые вы должны заботиться.
Поток закончен до того, как основной ждет. По этой причине я блокирую мьютекс перед тем, как запускать потоки.
б. Результат перезаписывается. Мне удалось это, проверив результат, прежде чем писать.
#include <thread>
#include <condition_variable>
#include <mutex>
std::mutex mtx;
std::condition_variable cv;
int result = -1;
void thread1()
{
// Do something
// ....
// ....
// got a result? publish it!
std::unique_lock<std::mutex> lck(mtx);
if (result != -1)
return; // there is already a result!
result = 0; // my result
cv.notify_one(); // say I am ready
}
void thread2()
{
// Do something else
// ....
// ....
// got a result? publish it!
std::unique_lock<std::mutex> lck(mtx);
if (result != -1)
return; // there is already a result!
result = 1; // my result
cv.notify_one(); // say I am ready
}
int main(int argc, char * argv[])
{
std::unique_lock<std::mutex> lck(mtx); // needed so the threads cannot finish befor wait
std::thread t1(thread1), t2(thread2);
cv.wait(lck); // wait until one result
// here result is 0 or 1;
// If you use the loop described below, you can use join safely:
t1.join();
t2.join();
// You have to call join or detach of std::thread objects before the
// destructor of std::thread is called.
return 0;
}
Если вы хотите остановить другой поток, если у него уже есть результат, единственный законный способ - часто тестировать результат в обоих потоках, если кто-то уже получил результат. В этом случае, если вы используете указатель или общий тип, вы должны пометить его volatile
модификатор. Вот как может выглядеть функция потока, если вы должны выполнять работу в цикле:
void thread1()
{
// Do something
bool bFinished=false;
while(!bFinished)
{
{ // this bracket is necessary to lock only the result test. Otherwise you got a deadlock a forced sync situation.
std::unique_lock<std::mutex> lck(mtx);
if (result != -1)
return; // there is already a result!
}
// do what ever you have to do
}
// got a result? publish it!
std::unique_lock<std::mutex> lck(mtx);
if (result != -1)
return; // there is already a result!
result = 0; // my result
cv.notify_one(); // say I am ready
}