многопоточность — C ++ Синхронизация потоков самым элегантным способом

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

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

Я хотел бы синхронизировать поток, так что будет запущен поток, который записывает 0, затем поток «печати», а затем поток, который пишет 1, а затем снова поток печати, и так далее …
Итак, наконец то, что я ожидаю увидеть на выходе потока «print», это последовательность нулей, затем последовательность 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;
}
}

1

Решение

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

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;
}

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

И Доброго Дня Бастилии всем французам!

0

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