1

Я пытаюсь решить следующую проблему: я знаю, что есть несколько решений, но я ищу самый элегантный способ (меньше кода) для его решения.C++ Синхронизация потоков самым элегантным способом

У меня 4 потока, 3 из них пытаются записать уникальное значение (0,1 или 2) в переменную целочисленного значения в бесконечном цикле, четвертый поток попытается прочитать значение этой переменной и распечатать значение для stdout также в бесконечном цикле.

Я хотел бы синхронизировать между потоком, поэтому будет выполняться поток, который пишет 0, а затем поток «print», а затем поток, который пишет 1, а затем снова поток печати, и так далее ... Так что, наконец, то, что я ожидаю увидеть на выходе «печатной» нити, представляет собой последовательность нулей, а затем последовательность 1, а затем 2, а затем 0 и т. Д.

Что является самым элегантным и легким способ синхронизации между этими потоками.

Это программный код:

volatile int value; 
int thid[4]; 

int main() { 
    HANDLE handle[4]; 
    for (int ii=0;ii<4;ii++) { 
     thid[ii]=ii; 
     handle[ii] = (HANDLE) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)     ThreadProc, &thid[ii], 0, NULL); 
    } 
    return 0; 
} 

void WINAPI ThreadProc(LPVOID param) { 
    int h=*((int*)param); 

    switch (h) { 
     case 3: 
      while(true) { 
       cout << value << endl; 
      } 
      break; 
     default: 
      while(true) { 
       // setting a unique value to the volatile variable 
       value=h; 
      } 
      break; 
    } 
} 
+3

Почему бы не использовать C++ 11 и 'atomic'? – Walter

+1

Для требуемого заказа вы должны использовать C++ 11 std :: condition_variable и std :: mutex. –

+0

atom on its own is no help, вам нужно что-то заблокировать поток 0 и дождаться, пока поток 3 обработает данные. Для этого требуется какая-то взаимная блокировка. –

ответ

0

Если вы хотите синхронизировать нити, а затем с помощью синхронизации объекта для хранения каждого из потоков в «пинг-понг» или «тик-так " шаблон. В C++ 11 вы можете использовать переменные состояния, пример here показывает что-то похожее на то, о чем вы просите.

+0

Это не совсем такой тип проблемы, так как здесь вам нужно управлять мусором планирования и установить его в этот порядок: thread 0, thread 3, thread 1, thread 3, нить 2, резьба 3, резьба 0, резьба 3 и т. Д. – Hawk89

+0

Да, это не совсем то же самое, но это тот же базовый принцип. –

0

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

https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem

Я использовал генератор случайных чисел для генерации летучих переменного, но вы можете изменить эту часть.

Вот код: его можно улучшить с точки зрения стиля (используя C++ 11 для случайных чисел), но он производит то, что вы ожидаете.

#include <iostream> 
#include <sstream> 
#include <vector> 
#include <stack> 
#include <thread> 
#include <mutex> 
#include <atomic> 
#include <condition_variable> 
#include <chrono> 
#include <stdlib.h>  /* srand, rand */ 
using namespace std; 

//random number generation 
std::mutex mutRand;//mutex for random number generation (given that the random generator is not thread safe). 
int GenerateNumber() 
{ 
    std::lock_guard<std::mutex> lk(mutRand); 
    return rand() % 3; 
} 

// print function for "thread safe" printing using a stringstream 
void print(ostream& s) { cout << s.rdbuf(); cout.flush(); s.clear(); } 

//  Constants 
// 
const int num_producers = 3;    //the three producers of random numbers 
const int num_consumers = 1;    //the only consumer 
const int producer_delay_to_produce = 10; // in miliseconds 
const int consumer_delay_to_consume = 30; // in miliseconds 

const int consumer_max_wait_time = 200;  // in miliseconds - max time that a consumer can wait for a product to be produced. 

const int max_production = 1;    // When producers has produced this quantity they will stop to produce 
const int max_products = 1;    // Maximum number of products that can be stored 

// 
//  Variables 
// 
atomic<int> num_producers_working(0);  // When there's no producer working the consumers will stop, and the program will stop. 
stack<int> products;      // The products stack, here we will store our products 
mutex xmutex;        // Our mutex, without this mutex our program will cry 

condition_variable is_not_full;    // to indicate that our stack is not full between the thread operations 
condition_variable is_not_empty;   // to indicate that our stack is not empty between the thread operations 

// 
//  Functions 
// 

//  Produce function, producer_id will produce a product 
void produce(int producer_id) 
{ 
    while (true) 
    { 
     unique_lock<mutex> lock(xmutex); 
     int product; 

     is_not_full.wait(lock, [] { return products.size() != max_products; }); 
     product = GenerateNumber(); 
     products.push(product); 

     print(stringstream() << "Producer " << producer_id << " produced " << product << "\n"); 
     is_not_empty.notify_all(); 
    } 

} 

//  Consume function, consumer_id will consume a product 
void consume(int consumer_id) 
{ 
    while (true) 
    { 
     unique_lock<mutex> lock(xmutex); 
     int product; 

     if(is_not_empty.wait_for(lock, chrono::milliseconds(consumer_max_wait_time), 
       [] { return products.size() > 0; })) 
     { 
       product = products.top(); 
       products.pop(); 

       print(stringstream() << "Consumer " << consumer_id << " consumed " << product << "\n"); 
       is_not_full.notify_all(); 
     } 
    } 

} 

//  Producer function, this is the body of a producer thread 
void producer(int id) 
{ 
     ++num_producers_working; 
     for(int i = 0; i < max_production; ++i) 
     { 
       produce(id); 
       this_thread::sleep_for(chrono::milliseconds(producer_delay_to_produce)); 
     } 

     print(stringstream() << "Producer " << id << " has exited\n"); 
     --num_producers_working; 
} 

//  Consumer function, this is the body of a consumer thread 
void consumer(int id) 
{ 
     // Wait until there is any producer working 
     while(num_producers_working == 0) this_thread::yield(); 

     while(num_producers_working != 0 || products.size() > 0) 
     { 
       consume(id); 
       this_thread::sleep_for(chrono::milliseconds(consumer_delay_to_consume)); 
     } 

     print(stringstream() << "Consumer " << id << " has exited\n"); 
} 

// 
//  Main 
// 

int main() 
{ 
     vector<thread> producers_and_consumers; 

     // Create producers 
     for(int i = 0; i < num_producers; ++i) 
       producers_and_consumers.push_back(thread(producer, i)); 

     // Create consumers 
     for(int i = 0; i < num_consumers; ++i) 
       producers_and_consumers.push_back(thread(consumer, i)); 

     // Wait for consumers and producers to finish 
     for(auto& t : producers_and_consumers) 
       t.join(); 
     return 0; 
} 

Надежда, что помогает, скажите мне, если вам нужно больше информации, или если вы не согласны с чем-то :-)

и хороший день взятия Бастилии ко всем французам!

Смежные вопросы