2009-02-17 09:45:57 +08:00
|
|
|
// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
|
2009-01-16 12:13:43 +08:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2012-12-08 22:32:13 +08:00
|
|
|
#include <dlib/threads.h>
|
|
|
|
#include <dlib/pipe.h>
|
|
|
|
#include <dlib/type_safe_union.h>
|
2009-01-16 12:13:43 +08:00
|
|
|
#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
|
2009-01-18 06:28:59 +08:00
|
|
|
// message_pipe.dequeue() to return false so our thread will terminate
|
2009-01-16 12:13:43 +08:00
|
|
|
message_pipe.disable();
|
|
|
|
|
2009-01-18 06:28:59 +08:00
|
|
|
// now block until our thread has terminated
|
2009-01-16 12:13:43 +08:00
|
|
|
wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Here we declare our pipe object. It will contain our messages.
|
2011-04-18 22:38:10 +08:00
|
|
|
dlib::pipe<tsu_type> message_pipe;
|
2009-01-16 12:13:43 +08:00
|
|
|
|
2009-05-21 09:41:29 +08:00
|
|
|
private:
|
2009-01-16 12:13:43 +08:00
|
|
|
|
|
|
|
// 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))
|
|
|
|
{
|
2009-05-21 09:41:29 +08:00
|
|
|
// 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.
|
2009-01-16 12:13:43 +08:00
|
|
|
msg.apply_to_contents(*this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-21 09:41:29 +08:00
|
|
|
// 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>;
|
|
|
|
|
2009-01-16 12:13:43 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
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
|
2009-01-19 08:27:18 +08:00
|
|
|
msg.get<float>() = 4.567f;
|
2009-01-16 12:13:43 +08:00
|
|
|
// 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.
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
|