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