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
|
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef KEA_THREAD_H
#define KEA_THREAD_H
#include <exceptions/exceptions.h>
#include <boost/noncopyable.hpp>
#include <boost/function.hpp>
namespace isc {
namespace util {
/// \brief Wrappers for thread related functionality
///
/// We provide our own wrappers, currently around pthreads. We tried using
/// the boost thread support, but it gave us some trouble, so we implemented
/// in-house ones.
namespace thread {
/// \brief A separate thread.
///
/// A thread of execution. When created, starts running in the background.
/// You can wait for it then or just forget it ever existed and leave it
/// live peacefully.
///
/// The interface is minimalist for now. We may need to extend it later.
///
/// \note While the objects of this class represent another thread, they
/// are not thread-safe. You're not supposed to call wait() on the same
/// object from multiple threads or so. They are reentrant (you can
/// wait for different threads from different threads).
class Thread : public boost::noncopyable {
public:
/// \brief There's an uncaught exception in a thread.
///
/// When a thread terminates because it the main function of the thread
/// throws, this one is re-thrown out of wait() and contains the what
/// of the original exception.
class UncaughtException : public isc::Exception {
public:
UncaughtException(const char* file, size_t line, const char* what) :
Exception(file, line, what)
{}
};
/// \brief Create and start a thread.
///
/// Create a new thread and run body inside it.
///
/// If you need to pass parameters to body, or return some result, you
/// may just want to use boost::bind or alike to store them within the
/// body functor.
///
/// \note The main functor will be copied internally. You need to consider
/// this when returning the result.
///
/// The body should terminate by exiting the function. If it throws, it
/// is considered an error. You should generally catch any exceptions form
/// within there and handle them somehow.
///
/// \param main The code to run inside the thread.
///
/// \throw std::bad_alloc if allocation of the new thread or other
/// resources fails.
/// \throw isc::InvalidOperation for other errors (should not happen).
Thread(const boost::function<void()>& main);
/// \brief Destructor.
///
/// It is completely legitimate to destroy the thread without calling
/// wait() before. In such case, the thread will just live on until it
/// terminates. However, if the thread dies due to exception, for example,
/// it's up to you to detect that, no error is reported from this class.
///
/// \throw isc::InvalidOperation in the rare case of OS reporting a
/// problem. This should not happen unless you messed up with the raw
/// thread by the low-level API.
~Thread();
/// \brief Wait for the thread to terminate.
///
/// Waits until the thread terminates. Must be called at most once.
///
/// \throw isc::InvalidOperation if the OS API returns error. This usually
/// mean a programmer error (like two threads trying to wait on each
/// other).
/// \throw isc::InvalidOperation calling wait a second time.
/// \throw UncaughtException if the thread terminated by throwing an
/// exception instead of just returning from the function.
void wait();
private:
class Impl;
Impl* impl_;
};
}
}
}
#endif
|