1

I'm programming a restaurant simulation in C++ to gain practice in the language, especially C++11 threads.

I intend on using a threaded server class (i.e a waiter) that can do the following:

  • receive notification of a new job being posted to a global table and take on the job (i.e seat a party that has just entered the restaurant)

  • receive notification of a party that is ready to place an order and take on the job (i.e visit the party's table, take their order and submit it to either the bar or kitchen's job queue)

  • receive a notification when an order is complete, taking the order from either the kitchen or bar and delivering it to the correct table

The big problem here is that my desired behavior is similar to waiting on several condition variables at the same time, which I have read is not possible from this post.

I would prefer to not use busy waiting, as these tasks could take up to a few minutes or more and that is a lot of unnecessary CPU consumption.

Most likely, I am thinking that I will want to employ some combination of condition variables and boost signals, but I am unsure of how I might design this to be most effective and concise.

Any suggestions on design or reading are highly appreciated.

Thanks in advance!

the_mackster
  • 153
  • 2
  • 9
  • 1
    Too broad/mostly opinion, there many possible approaches. Sorry, this kind of a question isn't a good fit for stackoverflow. – Sam Varshavchik Nov 08 '19 at 01:39
  • Since you mentioned a queue, a producer/consumer queue is a perfectly wait-able form of inter-thread communication: https://github.com/cameron314/readerwriterqueue – parktomatomi Nov 08 '19 at 04:15
  • @SamVarshavchik I'm sorry, but what about my post what opinion-based? I am trying my hardest not to be rude, but I find your comment to be uninformed and disgruntling. I am really just looking for potential design suggestions to tackle my use case. Does Stack Overflow forbid design questions? Please, enlighten me. I am new to the community. – the_mackster Nov 08 '19 at 06:43
  • @parktomatomi I appreciate the suggestion. Unfortunately, producer/consumer would only tackle 1/3 of the waiter's responsibility. – the_mackster Nov 08 '19 at 06:46
  • 1
    Yes, design questions are generally too broad/opinionated/off-topic for stackoverflow. This is because if you ask two C++ developers what's the best way to design X, you will get three different answers. – Sam Varshavchik Nov 08 '19 at 12:05

1 Answers1

1

When I need a thread to wait on multiple things at once, I find that select() works well as a base for implementing that behavior. In particular, you can set up select() to block until at least one of a specified set of sockets has data ready to read in its incoming-data-buffer.

So how is that useful when your program isn't about networking? Because you can call either pipe() or socketpair() before spawning your thread(s), and pass the receiving end of the pipe (or either end of the socketpair) to the thread for it to select() on. Then when another thread wants that thread to wake up and do something, it can write() a dummy byte to the other end of the pipe/socketpair, and that will cause the select()-ing thread to return from select(), whereupon FD_ISSET() will indicate that the receiving socket is ready-for-read. Based on that, the thread can then read() the dummy byte(s) received on its file descriptor (and throw them away), and then perform whatever action is appropriate. After that, it can call select() again to go back to sleep until the next incoming "trigger byte" is received.

The above is enough for simple "hey, do something now"-style communication if little or no data must be passed between threads; for more elaborate data-passing I usually combine the above triggering mechanism with some sort of Mutex-protected FIFO queue of command/message objects, such that the "triggering" thread adds one or more message-objects to the FIFO queue, then sends the dummy-byte, and the "receiving" thread, after waking up from select(), will grab all of the message-objects out of its FIFO queue and then handle each of them in turn.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • I really like this approach and did not even know `select()` existed, hence why I am doing this project in C++ (because I don't know the language that well). **THANK YOU** for not simply shunning my question. I truly appreciate it <3 – the_mackster Nov 08 '19 at 06:52