2015-11-08 5 views
0

Итак, у меня есть два потока, в которых они имеют одну и ту же переменную «counter». Я хочу синхронизировать свои потоки, продолжая выполнение только после того, как оба потока достигли этой точки. К сожалению, я вхожу в состояние взаимоблокировки, так как мой поток не меняет его контрольную переменную. Путь у меня есть это:Два потока, разделяющих переменную C++

volatile int counter = 0; 

    Thread() { 

      - some calculations - 

      counter++; 
      while(counter != 2) { 
       std::this_thread::yield(); 
      } 
      counter = 0; 

      - rest of the calculations - 
    } 

Идея заключается в том, что, поскольку у меня есть 2 потока, как только они достигают этой точки - в разное время - они будут увеличивать счетчик. Если счетчик не равен 2, то нить, которая достигла первой, должна будет ждать, пока другой увеличит счетчик так, чтобы они были синхронизированы. Кто-нибудь знает, где проблема здесь?

Чтобы добавить дополнительную информацию о проблеме, у меня есть два потока, которые выполняют половину операций над массивом. Как только они закончатся, я хочу убедиться, что они оба завершили расчеты. Как только они появятся, я могу сигнализировать о том, что поток принтера просыпается и выполняет операцию печати и очистки массива. Если я сделаю это до того, как оба потока завершатся, будут проблемы.

Псевдо код:

Thread() { 

    getLock() 
    1/2 of the calculations on array 
    releaseLock() 

    wait for both to finish - this is the issue 

    wake up printer thread 

} 
+0

Обычно, когда мы говорим о нити * синхронизации * мы говорим о принуждении нити для запуска * в последовательности * один за другим, а не * в то же время *. Кажется, вы пытаетесь сделать обратное. Можете ли вы объяснить, почему вы хотите, чтобы ваши потоки выполнялись одновременно? Кстати, невозможно точно знать, будут ли ваши потоки когда-либо запускаться одновременно, это зависит от планировщика ОС. – Galik

+0

Итак, я выполняю вычисления на массиве, которые разбиваются между двумя потоками. В конце я хочу распечатать и очистить этот массив, используя другой поток. Мне нужен один поток, чтобы разбудить поток печати, но мне нужно, чтобы оба потока завершили их выполнение в массиве, прежде чем я смогу просыпать поток принтера. Если они не синхронизированы, я получу массив, который не будет завершен. – QQCompi

+0

volatile не имеет места в многопоточности – Cubbi

ответ

1

В подобных ситуациях, вы должны использовать атомный счетчик.

std::atomic_uint counter = 0; 

В данном примере, нет также никаких признаков того, что counter был инициализирован.

+0

Я инициализировал его с помощью 'volatile int counter = 0;', но не могли бы вы помочь мне в использовании атомного счетчика? – QQCompi

+0

atomics - это способ управления C++ 11, оставляя 'volatile' для аппаратных интерфейсов.http://en.cppreference.com/w/cpp/atomic Еще одна проблема - выход - это только намек. Возможно, вы захотите «поспать». У меня есть комментарий ниже, который также может помочь. –

0

Возможно, вы ищете std::conditional_variable: условная переменная позволяет одному потоку сигнализировать о другом потоке. Поскольку это не похоже на использование счетчика, и вы используете его только для синхронизации, вот какой-то код от another answer (отказ от ответственности: это один из моих ответов), который показывает логику обработки std::conditional_variable на разных потоках и выполняет синхронизацию около значения:

unsigned int accountAmount; 
std::mutex mx; 
std::condition_variable cv; 

void depositMoney() 
{ 
    // go to the bank etc... 
    // wait in line... 
    { 
     std::unique_lock<std::mutex> lock(mx); 
     std::cout << "Depositing money" << std::endl; 
     accountAmount += 5000; 
    } 
    // Notify others we're finished 
    cv.notify_all(); 
} 
void withdrawMoney() 
{ 
    std::unique_lock<std::mutex> lock(mx); 
    // Wait until we know the money is there 
    cv.wait(lock); 
    std::cout << "Withdrawing money" << std::endl; 
    accountAmount -= 2000; 
} 
int main() 
{ 
    accountAmount = 0; 
    // Run both threads simultaneously: 
    std::thread deposit(&depositMoney); 
    std::thread withdraw(&withdrawMoney); 
    // Wait for both threads to finish 
    deposit.join(); 
    withdraw.join(); 
    std::cout << "All transactions processed. Final amount: " << accountAmount << std::endl; 
    return 0; 
} 
+0

Я считаю, что этот метод очень похож на реализацию типа cond_wait/cond_signal. Я не уверен, могу ли я использовать такую ​​реализацию из-за того, что два потока имеют одну и ту же функцию, если добавить ожидание вызова, оба начнут ждать. – QQCompi

+0

Это похоже, но другой подход состоял бы в том, чтобы иметь два объекта этого типа и переменную условия в их родительском (в логическом смысле), которая 'wait' до счетчика правильна. –

0

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

Вот простой пример:

#include <condition_variable> 
#include <mutex> 
#include <thread> 

class countdown_latch 
{ 
public: 
    countdown_latch(int count) 
     : count_(count) 
    { 
    } 

    void wait() 
    { 
     std::unique_lock<std::mutex> lock(mutex_); 
     while (count_ > 0) 
      condition_variable_.wait(lock); 
    } 

    void countdown() 
    { 
     std::lock_guard<std::mutex> lock(mutex_); 
     --count_; 
     if (count_ == 0) 
      condition_variable_.notify_all(); 
    } 

private: 
    int count_; 
    std::mutex mutex_; 
    std::condition_variable condition_variable_; 
}; 

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

std::atomic<int> result = 0; 
countdown_latch latch(2); 

void perform_work() 
{ 
    ++result; 
    latch.countdown(); 
} 

int main() 
{ 
    std::thread t1(perform_work); 
    std::thread t2(perform_work); 

    latch.wait(); 

    std::cout << "result = " << result; 

    t1.join(); 
    t2.join(); 
} 
Смежные вопросы