blob: 53998dbe8aa9646dbdca2064f481ea1c858ff3a8 (
plain)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
This is an example showing how to use the type_safe_union and pipe object from
from the dlib C++ Library to send messages between threads.
In this example we will create a class with a single thread in it. This thread
will receive messages from a pipe object and simply print them to the screen.
The interesting thing about this example is that it shows how to use a pipe and
type_safe_union to create a message channel between threads that can send many
different types of objects in a type safe manner.
Program output:
got a float: 4.567
got a string: string message
got an int: 7
got a string: yet another string message
*/
#include <dlib/threads.h>
#include <dlib/pipe.h>
#include <dlib/type_safe_union.h>
#include <iostream>
using namespace dlib;
using namespace std;
// ----------------------------------------------------------------------------------------
typedef type_safe_union<int, float, std::string> tsu_type;
/* This is a typedef for the type_safe_union we will be using in this example.
This type_safe_union object is a type-safe analogue of a union declared as follows:
union our_union_type
{
int a;
float b;
std::string c;
};
Note that the above union isn't actually valid C++ code because it contains a
non-POD type. That is, you can't put a std::string or any non-trivial
C++ class in a union. The type_safe_union, however, enables you to store non-POD
types such as the std::string.
*/
// ----------------------------------------------------------------------------------------
class pipe_example : private threaded_object
{
public:
pipe_example(
) :
message_pipe(4) // This 4 here is the size of our message_pipe. The significance is that
// if you try to enqueue more than 4 messages onto the pipe then enqueue() will
// block until there is room.
{
// start the thread
start();
}
~pipe_example (
)
{
// wait for all the messages to be processed
message_pipe.wait_until_empty();
// Now disable the message_pipe. Doing this will cause all calls to
// message_pipe.dequeue() to return false so our thread will terminate
message_pipe.disable();
// now block until our thread has terminated
wait();
}
// Here we declare our pipe object. It will contain our messages.
dlib::pipe<tsu_type> message_pipe;
private:
// When we call apply_to_contents() below these are the
// functions which get called.
void operator() (int val)
{
cout << "got an int: " << val << endl;
}
void operator() (float val)
{
cout << "got a float: " << val << endl;
}
void operator() (std::string val)
{
cout << "got a string: " << val << endl;
}
void thread ()
{
tsu_type msg;
// Here we loop on messages from the message_pipe.
while (message_pipe.dequeue(msg))
{
// Here we call the apply_to_contents() function on our type_safe_union.
// It takes a function object and applies that function object
// to the contents of the union. In our case we have setup
// the pipe_example class as our function object and so below we
// tell the msg object to take whatever it contains and
// call (*this)(contained_object); So what happens here is
// one of the three above functions gets called with the message
// we just got.
msg.apply_to_contents(*this);
}
}
// Finally, note that since we declared the operator() member functions
// private we need to declare the type_safe_union as a friend of this
// class so that it will be able to call them.
friend class type_safe_union<int, float, std::string>;
};
// ----------------------------------------------------------------------------------------
int main()
{
pipe_example pe;
// Make one of our type_safe_union objects
tsu_type msg;
// Treat our msg as a float and assign it 4.567
msg.get<float>() = 4.567f;
// Now put the message into the pipe
pe.message_pipe.enqueue(msg);
// Put a string into the pipe
msg.get<std::string>() = "string message";
pe.message_pipe.enqueue(msg);
// And now an int
msg.get<int>() = 7;
pe.message_pipe.enqueue(msg);
// And another string
msg.get<std::string>() = "yet another string message";
pe.message_pipe.enqueue(msg);
// the main function won't really terminate here. It will call the destructor for pe
// which will block until all the messages have been processed.
}
// ----------------------------------------------------------------------------------------
|