-1

I have a question about wait and notify multithreading in c++.

I have a container that deque<stack<string>> lines, which is like below.

deque(waiting line for cashier)

front(deque)

cart1 - item1 - item2 - item3


index 2(deque)

cart2 - item1 - item2


index 3(deque)

cart3 -item1 -item2 - item3

I have 5 cashier lanes (threads) And I want to allocate carts to each lanes and process calculation. I asked it to my teacher and he said I should use "wait and notify". I still don't understand threading clearly and I don't know how to implement shared resources threading..

jas
  • 11
  • 1
  • 2

3 Answers3

1

Very likely that wait and notify means:

For each thread (lane):

  • There is a queue of carts that are waiting to be checked out.

  • If the queue is empty then the thread (cashier) simply wait for some cart to be queued (simply sleeping, for not wasting CPU).

  • If a coordinator allocates / assigns a new cart to an empty queue then it should notify the associated thread (cashier) to wake up to process the checking out of the cart.

Then what you need here is to implement a queue structure that satisfies:

  • Thread-safe (by mutex)

  • Notifiable (by condition variable)

You can refer to this trivial implementation for more details.

duong_dajgja
  • 4,196
  • 1
  • 38
  • 65
0

Since you did not provide any code, we can just guess!

Well, you will most likely have some "cart pool" - like a central line waiting to be assigned to a cashier. Since multiple lanes can become "free" simultaneously you need to take care about tread-safety.

Threadsafety is easy, just create a central std::mutex and wrap the dequeue routine and empty central-lane checks in a {} scope that contains a std::scoped_lock(your_global_mutex).

Now, what happens when there is currently no cart waiting in the central line? Then all cashier threads must wait() until the central line notify()es about new carts being available. For that to work you must lock the cashier threads: You will need a condition variable and a mutex. Waiting goes like this and should be performed whenever one of those threads detects that the cart line is empty [but outside of the scoped lock]!

std::unique_lock<std::mutex> lk(your_condition_variable_mutex);
your_condition_variable.wait(lk, []{return i == 1;});

Make sure you have a global variable int i = 0; or something along the lines, because wait() can wake up sometimes for no reason - without the notify call().

Now, everytime you add a new cart to the main line, you set i=1 and call notiftAll() on your condition variable! (remember to set it back to 0 at the correct time - f.ex. shortly before taking out the last cart from the central line and guarded by the scoped_lock of the global mutex for example)

Skriptkiddie
  • 411
  • 2
  • 7
-1

Here a fully working code that solves your problem - forgive me the bad style with the goto's :) The explanation is in my other answer!

(note: compile it with 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;
}
Skriptkiddie
  • 411
  • 2
  • 7