2

I have mailBox class with send and receive methods shared between threads, and threads: thread1 send message, threads 2 and 3 receive messages, how I must using mutex for synchronize this?

Any combinations that I have tried hasn't led to success.

std::mutex g_lock; //in global
void sendMessage(Message msg) {
    if (g_lock.try_lock()) {
        this_thread::sleep_for(100ms); // DELAY
        messages->push_back(msg);
        g_lock.unlock();
    }
}

The same for Receive method

full code: https://pastebin.com/7y2RC5br

Also this code can't be debugged because delays change the logic of the code.

Correct logic of the code: thread2/3 try lock and read msg, get empty then unlock thread1 try lock and send msg then unlock thread2/3 try lock and read msg, get msg and write to file then unlock

When I have tried mutex's try_lock from threads 2/3, I had been getting constantly blocked thread and thread 1 was had been working after ALL threads 2/3.

Bence Kaulics
  • 7,066
  • 7
  • 33
  • 63
Dmitry Sokolov
  • 1,303
  • 1
  • 17
  • 29

1 Answers1

5

Box up low level mutexes into building block types.

Lock based thread safety is ridiculously easy to get wrong. Not only is it fragile, it doesn't compose; three routines that are pairwise thread safe can be when combined unsafe.

Thread safety is a relational property, not an absolute one.

There are various known patterns that have been mathematically proven to work. Implemented correctly and you are less doomed. Toss together something, and your code won't be correct.

To design new threading code you will want to get good at proof based computer science. The implementation is easier than designing it correctly.

In your case, I would start with a thread safe queue primitive. You'll need condition variables, mutexes, and a std deque. Then hook each routine up to one end of a queue, and send messages to the other. (The reader should only read from a queue and consume each message in order; the writer, only send messages on a queue).

I mean, this is still going to be hard to get right, but at least your primitives aren't nearly raw mutexes.

template<class T>
struct threadsafe_queue {
  T pop();
  void push(T);
  std::deque<T> pop_all();

  std::optional<T> try_pop();
  template<class...Ts>
  std::optional<T> wait_for_pop( std::chrono::duration<Ts...> );
private:
  mutable std::mutex m;
  std::condition_variable cv;
  std::deque<T> queue;
  std::unique_lock<std::mutex> lock() const;
};
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524