"docs/vscode:/vscode.git/clone" did not exist on "7eaae83f168e0d7ebca1ef238cbc58c5c46d39d9"
pipe_ex_2.cpp 4.92 KB
Newer Older
1
// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23


/*
    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
*/


24
25
26
#include <dlib/threads.h>
#include <dlib/pipe.h>
#include <dlib/type_safe_union.h>
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
#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 
Davis King's avatar
Davis King committed
73
        // message_pipe.dequeue() to return false so our thread will terminate
74
75
        message_pipe.disable();

Davis King's avatar
Davis King committed
76
        // now block until our thread has terminated
77
78
79
80
        wait();
    }

    // Here we declare our pipe object.  It will contain our messages.
81
    dlib::pipe<tsu_type> message_pipe;
82

Davis King's avatar
Davis King committed
83
private:
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

    // 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))
        {
Davis King's avatar
Davis King committed
109
110
111
112
113
114
115
116
            // 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.  
117
118
119
120
            msg.apply_to_contents(*this);
        }
    }

Davis King's avatar
Davis King committed
121
122
123
124
125
    // 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>;

126
127
128
129
130
131
132
133
134
135
136
137
};

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

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
Davis King's avatar
Davis King committed
138
    msg.get<float>() = 4.567f;
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
    // 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.
}

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