summaryrefslogtreecommitdiffstats
path: root/src/ml/dlib/examples/pipe_ex_2.cpp
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.
}

// ----------------------------------------------------------------------------------------