You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
2.9KB

  1. #pragma once
  2. #include <atomic>
  3. #include <mutex>
  4. #include <condition_variable>
  5. /**
  6. * Messaging protocol between client and server.
  7. *
  8. * This protocol has the following goals:
  9. * It is easy to implement.
  10. * It is easy to understand.
  11. * It is thread safe.
  12. * The client's thread will never block.
  13. *
  14. * Basics of the protocol:
  15. * Client initiates all communication.
  16. * For every message sent client -> server, the server will send once back.
  17. * The message objects are owned by whoever created them. Passing
  18. * a message does not transfer ownership.
  19. * Only one message may be "in play" at a time. Until the client
  20. * receives a reply from the server, it may not send another message.
  21. */
  22. /**
  23. * Base class for messages passed between client and server threads.
  24. * Receivers of message will typically examine the "type", and down-cast
  25. * based on that.
  26. */
  27. class ThreadMessage
  28. {
  29. public:
  30. enum class Type
  31. {
  32. TEST1,
  33. TEST2,
  34. NOISE // used by ColoredNoise
  35. };
  36. ThreadMessage(Type t) : type(t)
  37. {
  38. ++_dbgCount;
  39. }
  40. virtual ~ThreadMessage()
  41. {
  42. --_dbgCount;
  43. }
  44. const Type type;
  45. static std::atomic<int> _dbgCount;
  46. };
  47. /**
  48. * ThreadServer and ThreadClient do not refer to each other directly.
  49. * Instead, they both maintain pointers to ThreadSharedState.
  50. * All communication between thread goes through here.
  51. */
  52. class ThreadSharedState
  53. {
  54. public:
  55. ThreadSharedState()
  56. {
  57. ++_dbgCount;
  58. serverRunning.store(false);
  59. serverStopRequested.store(false);
  60. mailboxClient2Server.store(nullptr);
  61. mailboxServer2Client.store(nullptr);
  62. }
  63. ~ThreadSharedState()
  64. {
  65. --_dbgCount;
  66. }
  67. std::atomic<bool> serverRunning;
  68. std::atomic<bool> serverStopRequested;
  69. static std::atomic<int> _dbgCount;
  70. /**
  71. * If return false, message not sent.
  72. * otherwise message send, and msg may be reused.
  73. */
  74. bool client_trySendMessage(ThreadMessage* msg);
  75. ThreadMessage* client_pollMessage();
  76. void client_askServerToStop();
  77. void server_sendMessage(ThreadMessage* msg);
  78. /**
  79. * returned message is a pointer to a message that we "own"
  80. * temporarily (sender may modify it, but won't delete it).
  81. *
  82. * if null returned, a shutdown has been requested
  83. */
  84. ThreadMessage* server_waitForMessageOrShutdown();
  85. private:
  86. /**
  87. * This mutex protects all the private state
  88. */
  89. std::mutex mailboxMutex;
  90. /** The message in the mailbox.
  91. * This is an object by whoever created it. Ownership of message
  92. * is not passed.
  93. * TODO: given that a mutex protects us, we have no reason to use atomics here
  94. */
  95. std::atomic<ThreadMessage*> mailboxClient2Server;
  96. std::atomic<ThreadMessage*> mailboxServer2Client;
  97. std::condition_variable mailboxCondition;
  98. };