У меня есть вопрос о многопоточности ожидания и уведомления в C ++.
У меня есть контейнер, который deque<stack<string>> lines
, который, как показано ниже.
спереди (Deque)
cart1
— item1 — item2 — item3
индекс 2 (deque)
cart2 — item1
— пункт2
индекс 3 (deque)
cart3 -item1
-элемент2 — пункт3
У меня 5 кассовых дорожек (темы)
И я хочу выделить тележки для каждой дорожки и обработать расчет.
Я попросил об этом своего учителя, и он сказал, что я должен использовать «ждать и уведомить».
Я до сих пор не понимаю, что такое потоки, и я не знаю, как реализовать совместное использование ресурсов.
Очень вероятно, что wait and notify
средства:
Для каждой нити (полосы):
Есть очередь тележек, которые ждут, чтобы быть проверенными.
Если очередь пуста, то поток (кассир) просто wait
для некоторой корзины, которая будет поставлена в очередь (просто спит, чтобы не тратить процессор).
Если координатор выделяет / назначает новую корзину для пустой очереди, тогда он должен notify
связанный поток (кассир), чтобы проснуться, чтобы обработать извлечение из корзины.
Тогда вам нужно реализовать структуру очереди, которая удовлетворяет:
Потокобезопасный (по mutex
)
Уведомляемый (по condition variable
)
Вы можете обратиться к эта тривиальная реализация Больше подробностей.
Поскольку вы не предоставили никакого кода, мы можем только догадываться!
Что ж, у вас, скорее всего, будет некоторый «пул тележек» — например, центральная линия, ожидающая назначения кассиру. Поскольку несколько дорожек могут стать «свободными» одновременно, вам необходимо позаботиться о безопасности протектора.
Безопасность потоков — это просто, просто создайте центральный std :: mutex и оберните процедуру удаления очереди и пустые проверки центральной полосы в области {}, которая содержит std :: scoped_lock (your_global_mutex).
Теперь, что происходит, когда на центральной линии в данный момент нет тележки? Затем все потоки кассира должны ждать (), пока центральная линия не уведомит () о доступности новых тележек. Чтобы это работало, вы должны заблокировать потоки кассира:
Вам понадобится условная переменная и мьютекс. Ожидание происходит следующим образом и должно выполняться всякий раз, когда один из этих потоков обнаруживает, что строка корзины пуста [но за пределами блокировки области действия]!
std::unique_lock<std::mutex> lk(your_condition_variable_mutex);
your_condition_variable.wait(lk, []{return i == 1;});
Убедитесь, что у вас есть глобальная переменная
int i = 0;
или что-то в этом роде, потому что wait () может иногда просыпаться без причины — без вызова notify ().
Теперь, каждый раз, когда вы добавляете новую корзину в основную строку, вы устанавливаете i = 1 и вызываете notiftAll () для вашей условной переменной! (не забудьте установить его обратно в 0 в нужное время — например, незадолго до того, как вынуть последнюю тележку из центральной линии и, например, ее защищает scoped_lock глобального мьютекса)
Вот полностью рабочий код, который решает вашу проблему — простите мне плохой стиль с goto’s 🙂 Объяснение в моем другом ответе!
(примечание: скомпилируйте его с помощью pthread -> g ++ test.cc -pthread)
#include <stdio.h>
#include <condition_variable>
#include <thread>
#include <functional>
#include <iostream>
#include <stack>
volatile int i = 0;
std::mutex global_mutex;
std::mutex cond_mutex;
std::condition_variable cv;
std::stack<int> carts;
void cashier(int line){
int cart;
begin:
{
std::lock_guard<std::mutex> lc(global_mutex);
if(carts.size() == 0){
i = 0;
goto nah;
}
cart = carts.top();
carts.pop();
}
goto yay;
nah:
{
std::unique_lock<std::mutex> lk(cond_mutex);
{
std::lock_guard<std::mutex> lc(global_mutex);
std::cerr << "Cashier " << line << " Waiting... \n";
}
cv.wait(lk, []{return i == 1;});
goto begin;
}
yay:
{
std::lock_guard<std::mutex> lc(global_mutex);
std::cerr << "Cashier " << line << " got cart " << cart << " ... \n";
}
goto begin;
}
int main () {
std::thread t1(std::bind(cashier,1));
std::thread t2(std::bind(cashier,2));
std::thread t3(std::bind(cashier,3));
std::thread t4(std::bind(cashier,4));
std::thread t5(std::bind(cashier,5));
int cntr = 1;
printf("PRESS ENTER TO ENQUEUE NEW CART!!!\n");
while(getchar()){
{
std::lock_guard<std::mutex> lc(global_mutex);
carts.push(cntr);
cntr ++;
i = 1;
cv.notify_all();
}
}
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
return 0;
}