mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
230 Commits
boost-1.55
...
boost-1.56
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b2a61bca0 | ||
|
|
c6e70226ea | ||
|
|
5cdd807718 | ||
|
|
2a6948d74d | ||
|
|
590a3d99b0 | ||
|
|
14dfe49c50 | ||
|
|
08c4599fb6 | ||
|
|
ca14e6187d | ||
|
|
f263c6014e | ||
|
|
9e962e12e2 | ||
|
|
6e154d45a4 | ||
|
|
c54e519f72 | ||
|
|
5c61dced5e | ||
|
|
8a7f927be9 | ||
|
|
6074487b73 | ||
|
|
04c53415fd | ||
|
|
fe6daec2bc | ||
|
|
f75b2ca155 | ||
|
|
68be44ec06 | ||
|
|
817591b87c | ||
|
|
d7a3f124db | ||
|
|
c6817aeb1c | ||
|
|
c266790b8d | ||
|
|
00ad9dddb9 | ||
|
|
21617e1acb | ||
|
|
99ac322223 | ||
|
|
414fce4580 | ||
|
|
fe195e776b | ||
|
|
8a6d3d68ce | ||
|
|
3a5c926930 | ||
|
|
685ee1506a | ||
|
|
2062cebb54 | ||
|
|
126030eb8c | ||
|
|
ac1b9653f3 | ||
|
|
54ee07e745 | ||
|
|
ca298c2c86 | ||
|
|
4def87448e | ||
|
|
5719ea9e9f | ||
|
|
6583d87c92 | ||
|
|
fcf7a1811e | ||
|
|
d8f628ae65 | ||
|
|
0bd10b7244 | ||
|
|
24635c588f | ||
|
|
4f8106c00e | ||
|
|
3c4f1ea365 | ||
|
|
b5a50ab443 | ||
|
|
cb8a4a27bb | ||
|
|
8c0640e5be | ||
|
|
f807a678e0 | ||
|
|
49a1779d7f | ||
|
|
d3d2ad2390 | ||
|
|
abf844f50e | ||
|
|
4d52ef0740 | ||
|
|
40620e3d4b | ||
|
|
c3ab21a7ba | ||
|
|
c3002edc54 | ||
|
|
100bb706d6 | ||
|
|
de6a4df3a8 | ||
|
|
9669830a86 | ||
|
|
2937171413 | ||
|
|
dd0bfdd7ce | ||
|
|
89e340b177 | ||
|
|
c744899e45 | ||
|
|
0a4af0c5ed | ||
|
|
e6eb24d4a9 | ||
|
|
0d10e282fa | ||
|
|
e8181da6d4 | ||
|
|
68dc454a66 | ||
|
|
0e0ee99c61 | ||
|
|
f747d79c5b | ||
|
|
73fbc520e8 | ||
|
|
7d4f485ade | ||
|
|
143adde27d | ||
|
|
a7400061c6 | ||
|
|
d2a65d2427 | ||
|
|
82379f83a8 | ||
|
|
cc29295986 | ||
|
|
9d1c957625 | ||
|
|
1dbf7028fe | ||
|
|
0bba5e630e | ||
|
|
84c30313a2 | ||
|
|
54646e9959 | ||
|
|
3f5823f50a | ||
|
|
e1636bdbd5 | ||
|
|
750c849b0f | ||
|
|
0a05db8399 | ||
|
|
1d7da085ea | ||
|
|
75236fe3ae | ||
|
|
80634ee51e | ||
|
|
b1ac899f23 | ||
|
|
aa37de7aad | ||
|
|
9d527bebe0 | ||
|
|
f7c18c55bb | ||
|
|
1a2197c7f9 | ||
|
|
4a54ac0331 | ||
|
|
c6593d87b0 | ||
|
|
51e49c69b5 | ||
|
|
ab2a180de5 | ||
|
|
3772a8294b | ||
|
|
155ccfffbe | ||
|
|
bfa0ccee88 | ||
|
|
980772d514 | ||
|
|
94b27db991 | ||
|
|
0a58445b63 | ||
|
|
f02e25e4e7 | ||
|
|
acb117b5a9 | ||
|
|
8682f7cb48 | ||
|
|
4503c0e1da | ||
|
|
dc3397c452 | ||
|
|
af7fde5eae | ||
|
|
36bc3c0523 | ||
|
|
0218cb90b3 | ||
|
|
f4d4c16294 | ||
|
|
85d22a8d93 | ||
|
|
7eb67443dd | ||
|
|
4308e0ec24 | ||
|
|
ac9497dec9 | ||
|
|
8fec35f444 | ||
|
|
7b3fa08503 | ||
|
|
a2e1e80343 | ||
|
|
690feeb9ba | ||
|
|
5d76ab52e7 | ||
|
|
cb845f19e4 | ||
|
|
2886e985b4 | ||
|
|
f4d0ecbab5 | ||
|
|
d187732946 | ||
|
|
1fc78c7ceb | ||
|
|
5c18d92a5f | ||
|
|
06325961ef | ||
|
|
10b283e03a | ||
|
|
6ab71dc057 | ||
|
|
47be5228b1 | ||
|
|
6c5a6e4330 | ||
|
|
326842cc7f | ||
|
|
9f592860cd | ||
|
|
4148842426 | ||
|
|
7edae6614b | ||
|
|
2554065a91 | ||
|
|
74bb7d6b29 | ||
|
|
fbfda71555 | ||
|
|
f3a66f76e0 | ||
|
|
19346e1817 | ||
|
|
5753026ceb | ||
|
|
f6edd7cace | ||
|
|
126ed2428b | ||
|
|
fd631e2794 | ||
|
|
44f9a2f4ad | ||
|
|
8665c5d510 | ||
|
|
e1d6baddd6 | ||
|
|
9287a29c9d | ||
|
|
5c0cecaaf8 | ||
|
|
713f5a449c | ||
|
|
b336427571 | ||
|
|
2a16b649ad | ||
|
|
3723cedcab | ||
|
|
3ad582222c | ||
|
|
c9a33b8668 | ||
|
|
9138a2ae92 | ||
|
|
d558de7811 | ||
|
|
19290fddf9 | ||
|
|
2ac967d1dc | ||
|
|
6e81db4172 | ||
|
|
3a68a63478 | ||
|
|
7875edd234 | ||
|
|
2be0b4f8fd | ||
|
|
67528fc9af | ||
|
|
4da1e9dca1 | ||
|
|
d8c9be3449 | ||
|
|
f02390a804 | ||
|
|
955b207c05 | ||
|
|
8685c32d18 | ||
|
|
f51e8c812a | ||
|
|
51aff0fb00 | ||
|
|
bfe7af29bc | ||
|
|
4681104b33 | ||
|
|
d602f44af6 | ||
|
|
dc55945760 | ||
|
|
f7f0347780 | ||
|
|
d6c4be0cd0 | ||
|
|
e146febd70 | ||
|
|
67ca45ed83 | ||
|
|
cad6f2b9a6 | ||
|
|
7756df2ce0 | ||
|
|
ae831efe08 | ||
|
|
fc65611e82 | ||
|
|
67afa35c49 | ||
|
|
63d9ae2b29 | ||
|
|
08aa0d2fb6 | ||
|
|
3c8334f8c4 | ||
|
|
5bfa7cff41 | ||
|
|
e3a1498355 | ||
|
|
6fab117c17 | ||
|
|
4a63d4992c | ||
|
|
04e3d918fb | ||
|
|
0073516f0a | ||
|
|
89de3dcf4f | ||
|
|
47f40f991f | ||
|
|
8b351fe473 | ||
|
|
24f1e620e8 | ||
|
|
ed6459ecd2 | ||
|
|
858816b2d2 | ||
|
|
4bc70444a4 | ||
|
|
fcc027369f | ||
|
|
5c78582794 | ||
|
|
7f479a1dec | ||
|
|
4f2a7b2256 | ||
|
|
5c88e6ce61 | ||
|
|
650e374492 | ||
|
|
6319080ef2 | ||
|
|
3ac48bdd65 | ||
|
|
c3c8ada97d | ||
|
|
fd5dd0c2ed | ||
|
|
4a83aa58ed | ||
|
|
7d96aa625c | ||
|
|
d57a4c6565 | ||
|
|
c67e39f126 | ||
|
|
5a3c301582 | ||
|
|
dc5a8a9c4e | ||
|
|
1e49343ff4 | ||
|
|
93d1855e64 | ||
|
|
a39dd7e8b3 | ||
|
|
7e5cb92bab | ||
|
|
62cf0f86f6 | ||
|
|
c12e07754a | ||
|
|
cbc4266774 | ||
|
|
3a038d33e5 | ||
|
|
51ba4be998 | ||
|
|
2d50af8481 | ||
|
|
e438c98070 | ||
|
|
1e2a76de47 |
8
README.md
Normal file
8
README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
thread
|
||||
======
|
||||
|
||||
Portable C++ multi-threading. C++11, C++14.
|
||||
|
||||
### License
|
||||
|
||||
Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
|
||||
@@ -85,12 +85,12 @@ project boost/thread
|
||||
<toolset>clang:<cxxflags>-Wunused-function
|
||||
<toolset>clang:<cxxflags>-Wno-variadic-macros
|
||||
|
||||
<toolset>gcc-mingw-4.4.0:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.5.0:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.6.0:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.6.3:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.7.0:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.8.0:<cxxflags>-fdiagnostics-show-option
|
||||
#<toolset>gcc-mingw-4.4.0:<cxxflags>-fdiagnostics-show-option
|
||||
#<toolset>gcc-mingw-4.5.0:<cxxflags>-fdiagnostics-show-option
|
||||
#<toolset>gcc-mingw-4.6.0:<cxxflags>-fdiagnostics-show-option
|
||||
#<toolset>gcc-mingw-4.6.3:<cxxflags>-fdiagnostics-show-option
|
||||
#<toolset>gcc-mingw-4.7.0:<cxxflags>-fdiagnostics-show-option
|
||||
#<toolset>gcc-mingw-4.8.0:<cxxflags>-fdiagnostics-show-option
|
||||
#<toolset>gcc:<cxxflags>-Wno-missing-field-initializers
|
||||
|
||||
<toolset>darwin-4.6.2:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
|
||||
956
doc/async_executors.qbk
Normal file
956
doc/async_executors.qbk
Normal file
@@ -0,0 +1,956 @@
|
||||
[/
|
||||
/ Copyright (c) 2014 Vicente J. Botet Escriba
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
/]
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:executors Executors and Schedulers -- EXPERIMENTAL]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3785.pdf [*N3785 - Executors and Schedulers revision 3]] C++1y proposal from Chris Mysen, Niklas Gustafsson, Matt Austern, Jeffrey Yasskin. The text that follows has been adapted from tis paper to show the differences.]
|
||||
|
||||
Executors are objects that can execute units of work packaged as function objects. Boost.Thread differs from N3785 mainly in the an Executor doesn't needs to inherit from an abstract class Executor. Static polymorphism is used instead and type erasure is used internally.
|
||||
|
||||
[////////////////////]
|
||||
[section Introduction]
|
||||
|
||||
Multithreaded programs often involve discrete (sometimes small) units of work that are executed asynchronously. This often involves passing work units to some component that manages execution. We already have boost::async, which potentially executes a function asynchronously and eventually returns its result in a future. (“As if” by launching a new thread.)
|
||||
|
||||
If there is a regular stream of small work items then we almost certainly don’t want to launch a new thread for each, and it’s likely that we want at least some control over which thread(s) execute which items. It is often convenient to represent that control as multiple executor objects. This allows programs to start executors when necessary, switch from one executor to another to control execution policy, and use multiple executors to prevent interference and thread exhaustion. Several possible implementations exist of the executor class and in practice there are a number of main groups of executors which have been found to be useful in real-world code (more implementations exist, this is simply a high level classification of them). These differ along a couple main dimensions, how many execution contexts will be used, how they are selected, and how they are prioritized.
|
||||
|
||||
# Thread Pools
|
||||
# Simple unbounded thread pool, which can queue up an unbounded amount of work and maintains a dedicated set of threads (up to some maximum) which
|
||||
dequeue and execute work as available.
|
||||
# Bounded thread pools, which can be implemented as a specialization of the previous ones with a bounded queue or semaphore, which limits the amount of queuing in an attempt to bound the time spent waiting to execute and/or limit resource utilization for work tasks which hold state which is expensive to hold.
|
||||
# Thread-spawning executors, in which each work always executes in a new thread.
|
||||
# Prioritized thread pools, which have works which are not equally prioritized such that work can move to the front of the execution queue if necessary. This requires a special comparator or prioritization function to allow for work ordering and normally is implemented as a blocking priority queue in front of the pool instead of a blocking queue. This has many uses but is a somewhat specialized in nature and would unnecessarily clutter the initial interface.
|
||||
# Work stealing thread pools, this is a specialized use case and is encapsulated in the ForkJoinPool in java, which allows lightweight work to be created by tasks in the pool and either run by the same thread for invocation efficiency or stolen by another thread without additional work. These have been left out until there is a more concrete fork-join proposal or until there is a more clear need as these can be complicated to implement
|
||||
|
||||
# Mutual exclusion executors
|
||||
# Serial executors, which guarantee all work to be executed such that no two works will execute concurrently. This allows for a sequence of operations to be queued in sequence and that sequential order is maintained and work can be queued on a separate thread but with no mutual exclusion required.
|
||||
# Loop executor, in which one thread donates itself to the executor to execute all queued work. This is related to the serial executor in that it guarantees mutual exclusion, but instead guarantees a particular thread will execute the work. These are particularly useful for testing purposes where code assumes an executor but testing code desires control over execution.
|
||||
# GUI thread executor, where a GUI framework can expose an executor interface to allow other threads to queue up work to be executed as part of the GUI thread. This behaves similarly to a loop executor, but must be implemented as a custom interface as part of the framework.
|
||||
|
||||
# Inline executors, which execute inline to the thread which calls submit(). This has no queuing and behaves like a normal executor, but always uses the caller’s thread to execute. This allows parallel execution of works, though. This type of executor is often useful when there is an executor required by an interface, but when for performance reasons it’s better not to queue work or switch threads. This is often very useful as an optimization for work continuations which should execute immediately or quickly and can also be useful for optimizations when an interface requires an executor but the work tasks are too small to justify the overhead of a full thread pool.
|
||||
|
||||
A question arises of which of these executors (or others) be included in this library. There are use cases for these and many other executors. Often it is useful to have more than one implemented executor (e.g. the thread pool) to have more precise control of where the work is executed due to the existence of a GUI thread, or for testing purposes. A few core executors are frequently useful and these have been outlined here as the core of what should be in this library, if common use cases arise for alternative executor implementations, they can be added in the future. The current set provided here are: a basic thread pool `basic_thread_pool`, a serial executor `serial_executor`, a loop executor `loop_executor`, an inline executor `inline_executor` and a thread-spawning executor `thread_executor`.
|
||||
[endsect]
|
||||
|
||||
[/
|
||||
[/////////////////////////]
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
|
||||
[endsect]
|
||||
]
|
||||
[////////////////]
|
||||
[section:examples Examples]
|
||||
|
||||
[section:quick_sort Parallel Quick Sort]
|
||||
|
||||
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
template<typename T>
|
||||
struct sorter
|
||||
{
|
||||
boost::basic_thread_pool pool;
|
||||
typedef std::list<T> return_type;
|
||||
|
||||
std::list<T> do_sort(std::list<T> chunk_data)
|
||||
{
|
||||
if(chunk_data.empty()) {
|
||||
return chunk_data;
|
||||
}
|
||||
|
||||
std::list<T> result;
|
||||
result.splice(result.begin(),chunk_data, chunk_data.begin());
|
||||
T const& partition_val=*result.begin();
|
||||
|
||||
typename std::list<T>::iterator divide_point =
|
||||
std::partition(chunk_data.begin(), chunk_data.end(),
|
||||
[&](T const& val){return val<partition_val;});
|
||||
|
||||
std::list<T> new_lower_chunk;
|
||||
new_lower_chunk.splice(new_lower_chunk.end(), chunk_data,
|
||||
chunk_data.begin(), divide_point);
|
||||
boost::future<std::list<T> > new_lower =
|
||||
boost::async(pool, &sorter::do_sort, this, std::move(new_lower_chunk));
|
||||
std::list<T> new_higher(do_sort(chunk_data));
|
||||
result.splice(result.end(),new_higher);
|
||||
while(!new_lower.is_ready()) {
|
||||
pool.schedule_one_or_yield();
|
||||
}
|
||||
result.splice(result.begin(),new_lower.get());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::list<T> parallel_quick_sort(std::list<T>& input) {
|
||||
if(input.empty()) {
|
||||
return input;
|
||||
}
|
||||
sorter<T> s;
|
||||
return s.do_sort(input);
|
||||
}
|
||||
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
|
||||
[////////////////////////]
|
||||
[section:rationale Design Rationale]
|
||||
|
||||
The authors of Boost.Thread have taken a different approach respect to N3785. Instead of basing all the design on a abstract executor class we make executor concepts. We believe that this is the good direction as a static polymorphic executor can be seen as a dynamic polymorphic executor using a simple adaptor. We believe also that it would make the library more usable, and more convenient for users.
|
||||
|
||||
The major design decisions concern deciding what a unit of work is, how to manage with units of work and time related functions in a polymorphic way.
|
||||
|
||||
An Executor is an object that schedules the closures that have been submitted to it, usually asynchronously. There could be multiple models of the Executor class. Some specific design notes:
|
||||
|
||||
* Thread pools are well know models of the Executor concept, and this library does indeed include a basic_thread_pool class, but other implementations also exist, including the ability to schedule work on GUI threads, scheduling work on a donor thread, as well as several specializations of thread pools.
|
||||
|
||||
* The choice of which executor to use is explicit. This is important for reasons described in the Motivation section. In particular, consider the common case of an asynchronous operation that itself spawns asynchronous operations. If both operations ran on the same executor, and if that executor had a bounded number of worker threads, then we could get deadlock. Programs often deal with such issues by splitting different kinds of work between different executors.
|
||||
|
||||
* Even if there could be a strong value in having a default executor, that can be used when detailed control is unnecessary, the authors don't know how to implement it in a portable a robust way.
|
||||
|
||||
* The library provides Executors based on static and dynamic polymorphism. The static polymorphism interface is intended to be used on contexts that need to have the best performances. The dynamic polymorphism interface has the advantage to been able to change the executor a function is suing without making it a template and it possible to pass executors across a binary interface. For some applications, the cost of an additional virtual dispatch could be almost certainly negligible compared to the other operations involved.
|
||||
|
||||
* Conceptually, an executor puts closures on a queue and at some point executes them. The queue is always unbounded, so adding a closure to an executor never blocks. (Defining “never blocks” formally is challenging, but informally we just mean that submit() is an ordinary function that executes something and returns, rather than waiting for the completion of some potentially long running operation in another thread.)
|
||||
|
||||
[heading Closure]
|
||||
|
||||
One important question is just what a closure is. This library has a very simple answer: a closure is a `Callable` with no parameters and returning `voidv.
|
||||
|
||||
N3785 choose the more specific `std::function<void()>` as it provides only dynamic polymorphism and states that in practice the implementation of a template based approach or another approach is impractical. The authors of this library think that the template based approach is compatible with a dynamic based approach. They give some arguments:
|
||||
|
||||
The first one is that a virtual function can not be a template. This is true but it is also true that the executor interface can provide the template functions that call to the virtual public functions. Another reason they give is that "a template parameter would complicate the interface without adding any real generality. In the end an executor class is going to need some kind of type erasure to handle all the different kinds of function objects with `void()` signature, and that’s exactly what std::function already does". We think that it is up to the executor to manage with this implementation details, not to the user.
|
||||
|
||||
We share all the argument they give related to the `void()` interface of the work unit. A work unit is a closure that takes no arguments and returns no value. This is indeed a limitation on user code, but combined with `boost::async` taking executors as parameters the user has all what is needs.
|
||||
|
||||
The third one is related to performance. They assert that "any mechanism for storing closures on an executor’s queue will have to use some form of type erasure. There’s no reason to believe that a custom closure mechanism, written just for std::executor and used nowhere else within the standard library, would be better in that respect than `std::function<void()>`". We believe that the implementation can do better that storing the closure on a `std::function<void()>`. e.g. the implementation can use intrusive data to store the closure and the pointers to other nodes needed to store the closures in a given order.
|
||||
|
||||
In addition `std::function<void()>` can not be constructed by moving the closure, so e.g. `std::packaged_task` could not be a Closure.
|
||||
|
||||
[/
|
||||
[heading Scheduled work]
|
||||
|
||||
The approach of this library respect to scheduled work of the N3785 proposal is quite different. Instead of adding the scheduled operations to a specific scheduled_executor polymorphic interface, we opt by adding two member template functions to a class scheduled_executor that wraps an existing executor. This has several advantages:
|
||||
|
||||
* The scheduled operations are available for all the executors.
|
||||
* The template functions could accept any chrono `time_point` and `duration` respectively as we are not working with virtual functions.
|
||||
|
||||
In order to manage with all the clocks, there are two alternatives:
|
||||
|
||||
* transform the submit_at operation to a `submit_after` operation and let a single `scheduled_executor` manage with a single clock.
|
||||
* have a single instance of a `scheduled_executor<Clock>` for each `CLock`.
|
||||
|
||||
The library chose the first of those options, largely for simplicity.
|
||||
]
|
||||
|
||||
[heading Not Handled Exceptions]
|
||||
As in N3785 and based on the same design decision than `std`/`boost::thread` if a user closure throws an exception, the executor must call the `std::terminate` function.
|
||||
Note that when we combine `boost::async` and `Executors`, the exception will be caught by the closure associated to the returned future, so that the exception is stored on the returned future, as for the other `async` overloads.
|
||||
|
||||
[heading At thread entry]
|
||||
|
||||
It is common idiom to set some thread local variable at the beginning of a thread. As Executors could instantiate threads internally these Executors shall have the ability to call a user specific function at thread entry on the executor constructor.
|
||||
|
||||
For executors that don't instantiate any thread an that would use the current thread this function shall be called only for the thread calling the `at_thread_entry` member function.
|
||||
|
||||
[heading Cancelation]
|
||||
|
||||
The library does not provision yet for the ability to cancel/interrupt work, though this is a commonly requested feature.
|
||||
|
||||
This could be managed externally by an additional cancelation object that can be shared between the creator of the unit of work and the unit of work.
|
||||
|
||||
We can think also of a cancelable closure that could be used in a more transparent way.
|
||||
|
||||
An alternative is to make async return a cancelable_task but this will need also a cancelable closure.
|
||||
|
||||
|
||||
[/
|
||||
The library would provide in the future a cancelable_task that could support cancelation.
|
||||
|
||||
class cancelation_state {
|
||||
std::atomic<bool> requested; std::atomic<bool> enabled; std::condition_variable* cond; std::mutex cond_mutex;
|
||||
public:
|
||||
cancelation_state(): thread_cond(0) {} void cancel() { requested.store(true,std::memory_order_relaxed); std::lock_guard<std::mutex> lk(cond_mutex); if(cond) { cond->notify_all(); } } bool cancellation_requested() const { return requested.load(std::memory_order_relaxed); }
|
||||
void enable() { enable.store(true,std::memory_order_relaxed); } void disable() { enable.store(false,std::memory_order_relaxed); } bool cancellation_enabled() const { return enabled.load(std::memory_order_relaxed); } void set_condition_variable(std::condition_variable& cv) { std::lock_guard<std::mutex> lk(cond_mutex); cond = &cv; } void clear_condition_variable() { std::lock_guard<std::mutex> lk(cond_mutex); cond = 0; } struct clear_cv_on_destruct { ~clear_cv_on_destruct() { this_thread_interrupt_flag.clear_condition_variable(); } };
|
||||
void cancelation_point();
|
||||
void cancelable_wait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk) { cancelation_point(); this_cancelable_state.set_condition_variable(cv); this_cancelable_state::clear_cv_on_destruct guard; interruption_point();
|
||||
cv.wait_for(lk, std::chrono::milliseconds(1)); this_cancelable_state.clear_condition_variable(); cancelation_point(); }
|
||||
class disable_cancelation
|
||||
{
|
||||
public:
|
||||
disable_cancelation(const disable_cancelation&) = delete;
|
||||
disable_cancelation& operator=(const disable_cancelation&) = delete;
|
||||
disable_cancelation(cancelable_closure& closure) noexcept;
|
||||
~disable_cancelation() noexcept;
|
||||
};
|
||||
class restore_cancelation
|
||||
{
|
||||
public:
|
||||
restore_cancelation(const restore_cancelation&) = delete;
|
||||
restore_cancelation& operator=(const restore_cancelation&) = delete;
|
||||
explicit restore_cancelation(cancelable_closure& closure, disable_cancelation& disabler) noexcept;
|
||||
~restore_cancelation() noexcept;
|
||||
};
|
||||
};
|
||||
|
||||
template <class Closure>
|
||||
struct cancelable_closure_mixin : cancelable_closure {
|
||||
void operator() {
|
||||
cancel_point();
|
||||
this->Closure::run();
|
||||
}
|
||||
};
|
||||
|
||||
struct my_clousure : cancelable_closure_mixin<my_clousure>
|
||||
{
|
||||
void run() {
|
||||
while () {
|
||||
cancel_point();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
[heading Current executor]
|
||||
|
||||
The library does not provision for the ability to get the current executor, though having access to it could simplify a lot the user code.
|
||||
|
||||
The reason is that the user can always use a thread_local variable and reset it using the `at_thread_entry ` member function.
|
||||
|
||||
thread_local current_executor_state_type current_executor_state;
|
||||
executor* current_executor() { return current_executor_state.current_executor(); }
|
||||
basic_thread_pool pool(
|
||||
// at_thread_entry
|
||||
[](basic_thread_pool& pool) {
|
||||
current_executor_state.set_current_executor(pool);
|
||||
}
|
||||
);
|
||||
|
||||
[heading Default executor]
|
||||
|
||||
The library authors share some of the concerns of the C++ standard committee (introduction of a new single shared resource, a singleton, could make it difficult to make it portable to all the environments) and that this library doesn't need to provide a default executor for the time been.
|
||||
|
||||
The user can always define his default executor himself and use the `at_thread_entry ` member function to set the default constructor.
|
||||
|
||||
thread_local default_executor_state_type default_executor_state;
|
||||
executor* default_executor() { return default_executor_state.default_executor(); }
|
||||
|
||||
// in main
|
||||
MyDefaultExecutor myDefaultExecutor(
|
||||
// at_thread_entry
|
||||
[](MyDefaultExecutor& ex) {
|
||||
default_executor_state.set_default_executor(ex);
|
||||
}
|
||||
);
|
||||
|
||||
basic_thread_pool pool(
|
||||
// at_thread_entry
|
||||
[&myDefaultExecutor](basic_thread_pool& pool) {
|
||||
default_executor_state.set_default_executor(myDefaultExecutor);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////]
|
||||
[section:ref Reference]
|
||||
|
||||
|
||||
[////////////////////////////////]
|
||||
[section:concept_closure Concept `Closure`]
|
||||
|
||||
|
||||
A type `E` meets the `Closure` requirements if is a model of `Callable(void())` and a model of `CopyConstructible`/`MoveConstructible`.
|
||||
|
||||
[endsect]
|
||||
[////////////////////////////////]
|
||||
[section:concept_executor Concept `Executor`]
|
||||
|
||||
The `Executor` concept models the common operations of all the executors.
|
||||
|
||||
A type `E` meets the `Executor` requirements if the following expressions are well-formed and have the specified semantics
|
||||
|
||||
* `E::work`
|
||||
* `e.submit(lw);`
|
||||
* `e.submit(rw);`
|
||||
* `e.submit(lc);`
|
||||
* `e.submit(rc);`
|
||||
* `e.close();`
|
||||
* `b = e.closed();`
|
||||
* `e.try_executing_one();`
|
||||
* `e.reschedule_until(p);`
|
||||
|
||||
where
|
||||
|
||||
* `e` denotes a value of type `E`,
|
||||
* `lw` denotes a lvalue referece of type `E::work`,
|
||||
* `rc` denotes a rvalue referece of type `E::work`
|
||||
* `lc` denotes a lvalue referece of type `Closure`,
|
||||
* `rc` denotes a rvalue referece of type `Closure`
|
||||
* `p` denotes a value of type `Predicate`
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:submitlw `e.submit(lw);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
|
||||
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
|
||||
|
||||
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:submitrw `e.submit(rw);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
|
||||
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
|
||||
|
||||
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:submitlc `e.submit(lc);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
|
||||
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
|
||||
|
||||
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:submitrc `e.submit(lc);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
|
||||
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
|
||||
|
||||
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:close `e.close();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [close the executor `e` for submissions.]]
|
||||
|
||||
[[Remark:] [The worker threads will work until there is no more closures to run.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [Whatever exception that can be throw while ensuring the thread safety.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:close `b = e.close();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [`void`.]]
|
||||
|
||||
[[Throws:] [whether the pool is closed for submissions.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_executing_one `e.try_executing_one();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [try to execute one work.]]
|
||||
|
||||
[[Remark:] [whether a work has been executed.]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [Whether a work has been executed.]]
|
||||
|
||||
[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_executing_one `e.reschedule_until(p);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [This must be called from an scheduled work]]
|
||||
|
||||
[[Effects:] [reschedule works until `p()`.]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [Whether a work has been executed.]]
|
||||
|
||||
[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////]
|
||||
[section:work Class `work`]
|
||||
|
||||
#include <boost/thread/work.hpp>
|
||||
namespace boost {
|
||||
typedef 'implementation_defined' work;
|
||||
}
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [work is a model of 'Closure']]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////]
|
||||
[section:executor Class `executor`]
|
||||
|
||||
Executor abstract base class.
|
||||
|
||||
#include <boost/thread/executor.hpp>
|
||||
namespace boost {
|
||||
class executor
|
||||
{
|
||||
public:
|
||||
typedef boost::work work;
|
||||
|
||||
executor(executor const&) = delete;
|
||||
executor& operator=(executor const&) = delete;
|
||||
|
||||
executor();
|
||||
virtual ~executor() {};
|
||||
|
||||
virtual void close() = 0;
|
||||
virtual bool closed() = 0;
|
||||
|
||||
virtual void submit(work&& closure) = 0;
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
virtual bool try_executing_one() = 0;
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred);
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `executor()`]
|
||||
|
||||
executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a executor. ]]
|
||||
|
||||
[[Throws:] [Nothing. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Destructor `~executor()`]
|
||||
|
||||
virtual ~executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the executor.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:executor_adaptor Template Class `executor_adaptor`]
|
||||
|
||||
Polymorphic adaptor of a model of Executor to an executor.
|
||||
|
||||
#include <boost/thread/executor.hpp>
|
||||
namespace boost {
|
||||
template <typename Executor>
|
||||
class executor_adaptor : public executor
|
||||
{
|
||||
Executor ex; // for exposition only
|
||||
public:
|
||||
typedef executor::work work;
|
||||
|
||||
executor_adaptor(executor_adaptor const&) = delete;
|
||||
executor_adaptor& operator=(executor_adaptor const&) = delete;
|
||||
|
||||
template <typename ...Args>
|
||||
executor_adaptor(Args&& ... args);
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
void submit(work&& closure);
|
||||
|
||||
bool try_executing_one();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `executor_adaptor(Args&& ...)`]
|
||||
|
||||
template <typename ...Args>
|
||||
executor_adaptor(Args&& ... args);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a executor_adaptor. ]]
|
||||
|
||||
[[Throws:] [Nothing. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~executor_adaptor()`]
|
||||
|
||||
virtual ~ executor_adaptor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the executor_adaptor.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:underlying_executor Function member `underlying_executor()`]
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [The underlying executor instance. ]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[/
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:scheduled_executor Template Class `scheduled_executor`]
|
||||
|
||||
Executor providing time related functions.
|
||||
|
||||
#include <boost/thread/scheduled_executor.hpp>
|
||||
namespace boost {
|
||||
template <class Executor>
|
||||
class scheduled_executor
|
||||
{
|
||||
Executor& ex;
|
||||
public:
|
||||
typedef executor::work work;
|
||||
|
||||
scheduled_executor(scheduled_executor const&) = delete;
|
||||
scheduled_executor& operator=(scheduled_executor const&) = delete;
|
||||
|
||||
template <class Rep, class Period>
|
||||
scheduled_executor(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
void submit(work&& closure);
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
bool try_executing_one();
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred);
|
||||
|
||||
template <class Clock, class Duration>
|
||||
void submit_at(chrono::time_point<Clock,Duration> abs_time, work&& closure);
|
||||
template <class Rep, class Period>
|
||||
void submit_after(chrono::duration<Rep,Period> rel_time, work&& closure);
|
||||
template <class Clock, class Duration, typename Closure>
|
||||
void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);
|
||||
template <class Rep, class Period, typename Closure>
|
||||
void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `scheduled_executor(Executor&, chrono::duration<Rep, Period>)`]
|
||||
|
||||
template <class Rep, class Period>
|
||||
scheduled_executor(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a scheduled_executor. ]]
|
||||
|
||||
[[Throws:] [Nothing. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~scheduled_executor()`]
|
||||
|
||||
~scheduled_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the executor_adaptor.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:underlying_executor Function member `underlying_executor()`]
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [The underlying executor instance. ]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
]
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:scheduled_executor Template Class `serial_executor`]
|
||||
|
||||
A serial executor ensuring that there are no two work units that executes concurrently.
|
||||
|
||||
#include <boost/thread/serial_executor.hpp>
|
||||
namespace boost {
|
||||
template <class Executor>
|
||||
class serial_executor
|
||||
{
|
||||
Executor& ex;
|
||||
public:
|
||||
typedef executors::work work;
|
||||
|
||||
serial_executor(serial_executor const&) = delete;
|
||||
serial_executor& operator=(serial_executor const&) = delete;
|
||||
|
||||
serial_executor(Executor& ex);
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
void submit(work&& closure);
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
bool try_executing_one();
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `serial_executor(Executor&, chrono::duration<Rep, Period>)`]
|
||||
|
||||
serial_executor(Executor& ex);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a serial_executor. ]]
|
||||
|
||||
[[Throws:] [Nothing. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~serial_executor()`]
|
||||
|
||||
~serial_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the serial_executor.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:underlying_executor Function member `underlying_executor()`]
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [The underlying executor instance. ]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
[///////////////////////////////////////]
|
||||
[section:basic_thread_pool Class `basic_thread_pool`]
|
||||
|
||||
A thread pool with up to a fixed number of threads.
|
||||
|
||||
#include <boost/thread/work.hpp>
|
||||
namespace boost {
|
||||
class basic_thread_pool
|
||||
{
|
||||
public:
|
||||
typedef boost::work work;
|
||||
|
||||
basic_thread_pool(basic_thread_pool const&) = delete;
|
||||
basic_thread_pool& operator=(basic_thread_pool const&) = delete;
|
||||
|
||||
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency());
|
||||
template <class AtThreadEntry>
|
||||
basic_thread_pool( unsigned const thread_count, AtThreadEntry at_thread_entry);
|
||||
~basic_thread_pool();
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
bool try_executing_one();
|
||||
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `basic_thread_pool(unsigned const)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [creates a thread pool that runs closures on `thread_count` threads. ]]
|
||||
|
||||
[[Throws:] [Whatever exception is thrown while initializing the needed resources. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~basic_thread_pool()`]
|
||||
|
||||
virtual ~basic_thread_pool();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the thread pool.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////]
|
||||
[section:loop_executor Class `loop_executor`]
|
||||
|
||||
A user scheduled executor.
|
||||
|
||||
#include <boost/thread/loop_executor.hpp>
|
||||
namespace boost {
|
||||
class loop_executor
|
||||
{
|
||||
public:
|
||||
typedef thread_detail::work work;
|
||||
|
||||
loop_executor(loop_executor const&) = delete;
|
||||
loop_executor& operator=(loop_executor const&) = delete;
|
||||
|
||||
loop_executor();
|
||||
~loop_executor();
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
bool try_executing_one();
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred);
|
||||
|
||||
void loop();
|
||||
void run_queued_closures();
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `loop_executor()`]
|
||||
|
||||
loop_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [creates a executor that runs closures using one of its closure-executing methods. ]]
|
||||
|
||||
[[Throws:] [Whatever exception is thrown while initializing the needed resources. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~loop_executor()`]
|
||||
|
||||
virtual ~loop_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the thread pool.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:loop Function member `loop()`]
|
||||
|
||||
void loop();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [reschedule works until `closed()` or empty. ]]
|
||||
|
||||
[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:run_queued_closures Function member `run_queued_closures()`]
|
||||
|
||||
void run_queued_closures();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [reschedule the enqueued works. ]]
|
||||
|
||||
[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
@@ -1,6 +1,6 @@
|
||||
[/
|
||||
(C) Copyright 2007-11 Anthony Williams.
|
||||
(C) Copyright 2011-13 Vicente J. Botet Escriba.
|
||||
(C) Copyright 2011-14 Vicente J. Botet Escriba.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
@@ -8,6 +8,60 @@
|
||||
|
||||
[section:changes History]
|
||||
|
||||
[heading Version 4.3.0 - boost 1.56]
|
||||
|
||||
[*Know Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2442 #2442] Application statically linked with Boost.Thread crashes when Google Desktop is installed (Windows XP)
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6782 #6782] call_once uses incorrect barrier intrinsic on Visual Studio
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7319 #7319] Take care of c++std-lib-32966 issue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9307 #9307] future::fallback_to assert with ERRORRRRR boost: mutex lock failed in pthread_mutex_lock: Invalid argument
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9308 #9308] future::async fails with terminate called throwing an exception when called with a lambda - clang-darwin-asan11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9310 #9310] test_4648_lib fails on clang-darwin-asan11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9311 #9311] ex_lambda_future fails on msvc-11.0
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9425 #9425] Boost promise & future does not use supplied allocator for value storage
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9558 #9558] future continuations unit test hangs in get()/pthread_cond_wait() on Mac 10.7/32-bit/x86/darwin-4.2.1
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/release/developer/thread.html thread trunk regression test] to see the last snapshot.
|
||||
|
||||
|
||||
[*Sever limitations:]
|
||||
|
||||
There are some severe bugs that prevent the use of the library on concrete contexts, in particular:
|
||||
|
||||
* on thread specific storage that prevent the library to be used with dynamic libraries,
|
||||
* The experimental features of boost::future have some severe holes that make the program crash unexpectedly.
|
||||
|
||||
[*New Experimental Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7446 #7446] Async: Add when_any.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7447 #7447] Async: Add when_all.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7448 #7448] Async: Add async taking a scheduler parameter.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Synchro: Add concurrent queue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Synchro: Add a latch class.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8513 #8513] Async: Add a basic thread_pool executor.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8516 #8516] Async: Add future/shared_future::then taking a scheduler as parameter.
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8070 #8070] prefer GetTickCount64 over GetTickCount
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9333 #9333] ex_scoped_thread compile fails on msvc-12.0
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9366 #9366] async(Executor, ...) fails to compile with msvc-10,11,12
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9402 #9402] test_excutor regression on msvc-10,11,12
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9404 #9404] ex_make_future regression error
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9471 #9471] Synchronization documentation nits
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9535 #9535] Missing exception safety might result in crash
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9618 #9618] try_join_for problem: program is not terminate.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9673 #9673] thread compilation with MingW/gcc on Windows gives errors
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9708 #9708] boost::condition_variable::timed_wait unexpectedly wakes up while should wait infinite
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9711 #9711] future continuation called twice
|
||||
|
||||
[heading Version 4.2.0 - boost 1.55]
|
||||
|
||||
[*Know Bugs:]
|
||||
@@ -47,7 +101,7 @@ There are some severe bugs that prevent the use of the library on concrete conte
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7461 #7461] detail::win32::ReleaseSemaphore may be called with count_to_release equal to 0 Boost 1.55.0 closed viboes Bugs
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7461 #7461] detail::win32::ReleaseSemaphore may be called with count_to_release equal to 0
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8070 #8070] prefer GetTickCount64 over GetTickCount
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8768 #8768] win32 condition_variable::wait_until infinite wait in rare cases.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8817 #8817] Boost Thread Windows CE _createthreadex handling breaks mingw w64.
|
||||
@@ -449,10 +503,7 @@ The following features will be included in next releases.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7589 #7589] Synchro: Add polymorphic lockables.
|
||||
|
||||
# Add some features based on C++ proposals, in particular
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Synchro: Add concurrent queue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Synchro: Add a latch class.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Synchro: Add externally locked streams.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8513 #8513] Async: Add a basic thread_pool executor.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8514 #8514] Async: Add a thread_pool executor with work stealing.
|
||||
|
||||
# Add some of the extension proposed in [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf A Standardized Representation of Asynchronous Operations] or extension to them, in particular
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[/
|
||||
(C) Copyright 2011-12 Vicente J. Botet Escriba.
|
||||
(C) Copyright 2011-2013 Vicente J. Botet Escriba.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
[section:cpp11 C++11 standard Thread library]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.html C++11 standard]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.html C++11 - Standard for Programming Language C++]]]
|
||||
|
||||
|
||||
[table C++11 standard Conformance
|
||||
@@ -73,24 +73,23 @@
|
||||
[[30.6.9] [Class template packaged_task] [Yes] [-] [-]]
|
||||
]
|
||||
|
||||
[/
|
||||
|
||||
[table Extension
|
||||
[[Section] [Description] [Comments]]
|
||||
[[30.3.1.5.x] [interrupt] [-]]
|
||||
[[30.3.2.x] [Interruption] [-]]
|
||||
[[30.3.2.y] [at_thread_exit] [-]]
|
||||
[[30.4.3.x] [Generic locking algorithms begin/end] [-]]
|
||||
[[30.x] [Barriers] [-]]
|
||||
[[30.y] [Thread Local Storage] [-]]
|
||||
[[30.z] [Class thread_group] [-]]
|
||||
]
|
||||
|
||||
[/
|
||||
[[30.x] [Thread Local Storage] [-]]
|
||||
[[30.y] [Class thread_group] [-]]
|
||||
]
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:cxx14 C++14 standard Thread library - accepted changes]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.html C++14 on-going standard]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.html Working Draft, Standard for Programming Language C++]]
|
||||
|
||||
|
||||
[table [@http://isocpp.org/files/papers/N3659.html N3659 Shared locking in C++ revision 2] Conformance
|
||||
@@ -106,8 +105,8 @@
|
||||
|
||||
[section:latch C++ Latches and Barriers]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3600.html N3659 C++ Latches and Barriers]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3666.html N3659 C++ Latches and Barriers]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3600.html N3600 C++ Latches and Barriers]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3817.html N3817 C++ Latches and Barriers]]
|
||||
|
||||
[table C++ Latches and Barriers Conformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
@@ -124,105 +123,103 @@
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[X.1] [Conceptual interface] [Partial] [ The interface provided has some differences respect to this proposal. All the functions having a queue_op_status are not provided. No lock-free concrete classes ]]
|
||||
[[X.1.1] [Basic Operations] [Partial] [ - ]]
|
||||
[[X.1.1.1] [push] [yes] [ - ]]
|
||||
[[X.1.1.2] [value_pop] [no] [ renamed pull with two flavors + a ptr_pull that returns a sharted_ptr<>. ]]
|
||||
[[X.1.1.1] [push] [yes] [ renamed push_back. ]]
|
||||
[[X.1.1.2] [value_pop] [no] [ renamed pull_front with two flavors. ]]
|
||||
[[X.1.2] [Non-waiting operations] [ - ] [ - ]]
|
||||
[[X.1.2.1] [try_push] [Partial] [ return bool instead ]]
|
||||
[[X.1.2.2] [try_pop] [Partial] [ renamed try_pull, returns null ]]
|
||||
[[X.1.2.1] [try_push] [yes] [ renamed try_push_back ]]
|
||||
[[X.1.2.2] [try_pop] [yes] [ renamed try_pull_back ]]
|
||||
[[X.1.3] [Non-blocking operations] [ - ] [ - ]]
|
||||
[[X.1.3.1] [nonblocking_push] [Partial] [ renamed try_push(no_block, ]]
|
||||
[[X.1.3.2] [nonblocking_pop] [Partial] [ renamed try_pop(no_block, ]]
|
||||
[[X.1.3.1] [nonblocking_push] [Yes] [ renamed nonblocking_push_back ]]
|
||||
[[X.1.3.2] [nonblocking_pop] [Yes] [ renamed nonblocking_pull_front ]]
|
||||
[[X.1.4] [Push-front operations] [No] [ - ]]
|
||||
[[X.1.5] [Closed queues] [Partial] [ - ]]
|
||||
[[X.1.5.1] [close] [Yes] [ - ]]
|
||||
[[X.1.5.2] [is_closed] [Yes] [ - ]]
|
||||
[[X.1.5.3] [wait_push] [Partial] [ - ]]
|
||||
[[X.1.5.4] [wait_pop] [Partial] [ - ]]
|
||||
[[X.1.5.2] [is_closed] [Yes] [ renamed closed ]]
|
||||
[[X.1.5.3] [wait_push] [Yes] [ renamed wait_push_back ]]
|
||||
[[X.1.5.4] [wait_pop] [Yes] [ renamed wait_pull_front ]]
|
||||
[[X.1.5.5] [wait_push_front] [no] [ - ]]
|
||||
[[X.1.5.6] [wait_pop] [Partial] [ - ]]
|
||||
[[X.1.5.6] [wait_pop_back] [no] [ - ]]
|
||||
[[X.1.5.6] [open] [no] [ - ]]
|
||||
[[X.1.6] [Empty and Full Queues] [Yes] [ - ]]
|
||||
[[X.1.6.1] [is_empty] [Yes] [ - ]]
|
||||
[[X.1.6.2] [is_full] [Yes] [ Added capacity ]]
|
||||
[[X.1.7] [Queue Names] [No] [ Not considere a must for the time been. ]]
|
||||
[[X.1.7] [Queue Names] [No] [ Not considered a must for the time been. ]]
|
||||
[[X.1.8] [Element Type Requirements] [Yes?] [ - ]]
|
||||
[[X.1.9] [Exception Handling] [Yes?] [ - ]]
|
||||
[[X.1.10] [Queue Ordering] [Yes?] [ - ]]
|
||||
[[X.1.11] [Lock-Free Implementations] [No] [ waiting to stabilize the lock-based interface. Will use Boost.LockFree once it is Move aware. ]]
|
||||
[[X.1.11] [Lock-Free Implementations] [No] [ waiting to stabilize the lock-based interface. Will use Boost.LockFree once it is Boost.Move aware. ]]
|
||||
[[X.2] [Concrete queues] [Partial] [ - ]]
|
||||
[[X.2.1] [Locking Buffer Queue] [Partial] [ classes sync_queue and a sync_bounded_queue. ]]
|
||||
[[X.2.1] [Lock-Free Buffer Queue] [No] [ - ]]
|
||||
[[X.2.1] [Lock-Free Buffer Queue] [No] [ waiting to stabilize the lock-based interface. Will use Boost.LockFree once it is Boost.Move aware. ]]
|
||||
[[X.3] [Additional Conceptual Tools] [No] [ - ]]
|
||||
[[X.3.1] [Fronts and Backs] [No] [ - ]]
|
||||
[[X.3.2] [Streaming Iterators] [No] [ - ]]
|
||||
[[X.3.2] [Streaming Iterators] [No] [ - ]]
|
||||
[[X.3.3] [Storage Iterators] [No] [ - ]]
|
||||
[[X.3.4] [Binary Interfaces] [No] [ - ]]
|
||||
[[X.3.4] [Managed Indirection] [No] [ - ]]
|
||||
]
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:executors Asynchronous Executors]
|
||||
|
||||
While Boost.Thread implementation of executors would not use dynamic polymorphism, it is worth comparing with the current trend on the standard.
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3378.pdf N3378 A preliminary proposal for work executors]]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3785.pdf N3785 Executors and Schedulers]]
|
||||
|
||||
[table Asynchronous Executors
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[30.X.1] [Class executor] [No] [ - ]]
|
||||
[[30.X.1.1] [add] [No] [ renamed with a function template submit ]]
|
||||
[[30.X.1.1] [num_of_pendin_closures] [??] [ ]]
|
||||
[[30.X.2] [Class sceduled_executor] [No] [ - ]]
|
||||
[[30.X.2.1] [add_at] [No] [ renamed with a function template submit_at ]]
|
||||
[[30.X.2.2] [add_after] [No] [ renamed with a function template submit_after ]]
|
||||
[[30.X.3] [Executor utilities functions] [No] [ - ]]
|
||||
[[30.X.3.1] [default_executor] [No] [ - ]]
|
||||
[[30.X.3.2] [set_default_executor] [No] [ - ]]
|
||||
[[30.X.3.3] [singleton_inline_executor] [No] [ - ]]
|
||||
[[30.X.4] [Concrete executor classes] [No] [ - ]]
|
||||
[[30.X.4.1] [loop_executor] [No] [ - ]]
|
||||
[[30.X.4.1] [serial_executor] [No] [ - ]]
|
||||
[[30.X.4.1] [thread_pool] [No] [ #8513 ]]
|
||||
[[V.1.1] [Class executor] [Yes] [ - ]]
|
||||
[[V.1.1] [add] [Yes] [ renamed with a function template submit ]]
|
||||
[[V.1.1] [num_of_pendin_closures] [No] [ ]]
|
||||
[[V.1.2] [Class sceduled_executor] [No] [ - ]]
|
||||
[[V.1.2] [add_at] [No] [ renamed with a function template submit_at ]]
|
||||
[[V.1.2] [add_after] [No] [ renamed with a function template submit_after ]]
|
||||
[[V.2] [Concrete executor classes] [No] [ - ]]
|
||||
[[V.2.1] [thread_pool] [Yes] [ static version Basic_thread_pool, dynamic one execduler_adaptor<basic_thread_pool> ]]
|
||||
[[V.2.2] [serial_executor] [yes] [ - ]]
|
||||
[[V.2.3] [loop_executor] [Yes] [ static version loop_scheduler, dynamic one execduler_adaptor<loop_scheduler> ]]
|
||||
[[V.2.4] [inline_executor] [Yes] [ static version inline_executor, dynamic one execduler_adaptor<inline_executor> ]]
|
||||
[[V.2.5] [thread_executor] [Yes] [ static version thread_executor, dynamic one execduler_adaptor<thread_executor> ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:async Improvements to std::future<T> and Related APIs]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3857.pdf N3857-Improvements to std::future<T> and Related APIs]]
|
||||
|
||||
[section:async A Standardized Representation of Asynchronous Operations]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3558.pdf N3558 A Standardized Representation of Asynchronous Operations]]
|
||||
[note These functions are based on the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3634.pdf [*N3634 - Improvements to std::future<T> and related APIs]] C++1y proposal by N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani.]
|
||||
[note These functions are based on [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3634.pdf [*N3634 - Improvements to std::future<T> and related APIs]] C++1y proposal by N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani.]
|
||||
|
||||
[table Improvements to std::future<T> and related APIs]
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[30.6.6] [Class template future] [Partial] [ - ]]
|
||||
[[30.6.6.1] [then] [Partial] [ executor interface missing #8516 ]]
|
||||
[[30.6.6.2] [unwrap] [Yes] [ - ]]
|
||||
[[30.6.6.3] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.6] [unwrap constructor] [Yes] [ - ]]
|
||||
[[30.6.6] [then] [Yes] [ - ]]
|
||||
[[30.6.6] [unwrap] [Yes] [ - ]]
|
||||
[[30.6.6] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.7] [Class template shared_future] [Partial] [ - ]]
|
||||
[[30.6.7.1] [then] [Yes] [ executor interface missing #8516 ]]
|
||||
[[30.6.7.2] [unwrap] [No] [ #XXXX ]]
|
||||
[[30.6.7.3] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.X] [Function template when_any] [No] [ #7446 ]]
|
||||
[[30.6.X] [Function template when_all] [No] [ #7447 ]]
|
||||
[[30.6.6] [unwrap constructor] [Yes] [ - ]]
|
||||
[[30.6.7] [then] [Yes] [ - ]]
|
||||
[[30.6.7] [unwrap] [No] [ #XXXX ]]
|
||||
[[30.6.7] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.X] [Function template when_all] [Partial] [ interface not complete #7447 ]]
|
||||
[[30.6.X] [Function template when_any] [Partial] [ interface not complete #7446 ]]
|
||||
[[30.6.X] [Function template when_any_swaped] [No] [ #XXXX ]]
|
||||
[[30.6.X] [Function template make_ready_future] [Yes] [ - ]]
|
||||
[[30.6.8] [Function template async ] [No] [ executor interface missing #7448 ]]
|
||||
[[30.6.8] [Function template async ] [Yes] [ - ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:stream_mutex C++ Stream Mutexes - C++ Stream Guards]
|
||||
|
||||
While Boost.Thread implementation of stream mutexes differ in the approach, it is worth comparing with the current trend on the standard.
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3535.html N3535 - C++ Stream Mutexes]. This has been replaced already by N3678 - C++ Stream Guards.]
|
||||
[note These functions are based on [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3535.html [*N3535 - C++ Stream Mutexes]] by Lawrence Crowl.]
|
||||
|
||||
[table C++ C++ Stream MutexesConformance
|
||||
[note This proposal has been replaced already by [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3678.html N3678 - C++ Stream Guards], which has been replaced by [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3678.html N3665 - Uninterleaved String Output Streaming] and [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3678.html N3750 - C++ Ostream Buffers]]
|
||||
|
||||
[table C++ Stream Mutexes Conformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[X.1] [Class template stream_mutex] [Partial] [ externally_locked_stream<> ]]
|
||||
[[X.2.1] [constructor] [Partial] [ externally_locked_stream needs a mutex in addition as argumement. ]]
|
||||
[[X.1] [Class template stream_mutex] [Partial] [ Renamed externally_locked_stream<> ]]
|
||||
[[X.2.1] [constructor] [Partial] [ externally_locked_stream needs a mutex in addition as argument. ]]
|
||||
[[X.2.2] [lock] [yes] [ - ]]
|
||||
[[X.2.3] [unlock] [yes] [ - ]]
|
||||
[[X.2.4] [try_lock] [yes] [ - ]]
|
||||
@@ -232,12 +229,10 @@ While Boost.Thread implementation of stream mutexes differ in the approach, it i
|
||||
[[X.2.1] [stream_guard] [Yes] [ - ]]
|
||||
[[X.2.2] [~stream_guard] [Yes] [ - ]]
|
||||
[[X.2.3] [bypass] [Yes] [ - ]]
|
||||
[[X.3] [Stream Operators] [Yes] [.]]
|
||||
[[X.4] [Predefined Objects] [No] [.]]
|
||||
[[X.3] [Stream Operators] [Yes] [-]]
|
||||
[[X.4] [Predefined Objects] [No] [-]]
|
||||
]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3678.html N3678 - C++ Stream Guards]]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -304,8 +304,12 @@ When `BOOST_THREAD_VERSION>=4` define `BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKA
|
||||
|
||||
C++11 thread constructor accep a variable number of rvalue argumentshas. When `BOOST_THREAD_PROVIDES_VARIADIC_THREAD ` is defined Boost.Thread provides this C++ feature if the following are not defined
|
||||
|
||||
* BOOST_NO_SFINAE_EXPR
|
||||
* BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
* BOOST_NO_CXX11_DECLTYPE
|
||||
* BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
* BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
* BOOST_NO_CXX11_TRAILING_RESULT_TYPES
|
||||
* BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
* BOOST_NO_CXX11_HDR_TUPLE
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[/
|
||||
/ Copyright (c) 2008,2012 Vicente J. Botet Escriba
|
||||
/ Copyright (c) 2008,2012,2014 Vicente J. Botet Escriba
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
[section External Locking -- `strict_lock` and `externally_locked` classes]
|
||||
|
||||
|
||||
[note This tutorial is an adaptation of the paper of Andrei Alexandrescu "Multithreading and the C++ Type System"
|
||||
[note This tutorial is an adaptation of the paper by Andrei Alexandrescu "Multithreading and the C++ Type System"
|
||||
to the Boost library.]
|
||||
|
||||
[/
|
||||
@@ -163,7 +163,7 @@ Obviously, the caller-ensured locking approach has a safety problem. BankAccount
|
||||
To conclude, if in designing a multi-threaded class you settle on internal locking, you expose yourself to inefficiency or deadlocks. On the other hand, if you rely on caller-provided locking, you make your class error-prone and difficult to use. Finally, external locking completely avoids the issue by leaving it all to the client code.
|
||||
[endsect]
|
||||
]
|
||||
[section Locks as Permits]
|
||||
[section Locks as permits]
|
||||
|
||||
So what to do? Ideally, the BankAccount class should do the following:
|
||||
|
||||
@@ -182,9 +182,9 @@ For now, let's make a couple of enhancements to the `lock_guard` class template
|
||||
We'll call the enhanced version `strict_lock`. Essentially, a `strict_lock`'s role is only to live on the stack as an automatic variable.
|
||||
`strict_lock` must adhere to a non-copy and non-alias policy.
|
||||
`strict_lock` disables copying by making the copy constructor and the assignment operator private.
|
||||
[/
|
||||
While we're at it, let's disable operator new and operator delete.
|
||||
|
||||
[/
|
||||
`strict_lock` are not intended to be allocated on the heap.
|
||||
`strict_lock` avoids aliasing by using a slightly less orthodox and less well-known technique: disable address taking.
|
||||
]
|
||||
@@ -293,7 +293,7 @@ A little code is worth 1,000 words, a (hacked into) saying goes, so here's the n
|
||||
}
|
||||
};
|
||||
|
||||
Now, if you want the benefit of internal locking, you simply call Deposit(int) and Withdraw(int). If you want to use external locking, you lock the object by constructing a `strict_lock<BankAccount>` and then you call `Deposit(int, strict_lock<BankAccount>&)` and `Withdraw(int, strict_lock<BankAccount>&)`. For example, here's the `ATMWithdrawal` function implemented correctly:
|
||||
Now, if you want the benefit of internal locking, you simply call `Deposit(int)` and `Withdraw(int)`. If you want to use external locking, you lock the object by constructing a `strict_lock<BankAccount>` and then you call `Deposit(int, strict_lock<BankAccount>&)` and `Withdraw(int, strict_lock<BankAccount>&)`. For example, here's the `ATMWithdrawal` function implemented correctly:
|
||||
|
||||
void ATMWithdrawal(BankAccount& acct, int sum) {
|
||||
strict_lock<BankAccount> guard(acct);
|
||||
@@ -453,7 +453,7 @@ We achieved two important goals. First, the declaration of `checkingAcct_` and `
|
||||
|
||||
[section Allowing other strict locks]
|
||||
|
||||
Now imagine that the AccountManager function needs to take a `unique_lock` in order to reduce the critical regions. And at some time it needs to access to the `checkingAcct_`. As `unique_lock` is not a strict lock the following code doesn't compiles:
|
||||
Now imagine that the AccountManager function needs to take a `unique_lock` in order to reduce the critical regions. And at some time it needs to access to the `checkingAcct_`. As `unique_lock` is not a strict lock the following code doesn't compile:
|
||||
|
||||
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
|
||||
unique_lock<AccountManager> guard(*this, defer_lock);
|
||||
@@ -465,7 +465,7 @@ Now imagine that the AccountManager function needs to take a `unique_lock` in or
|
||||
do_something_else();
|
||||
}
|
||||
|
||||
We need a way to transfer the ownership from the `unique_lock` to a `strict_lock` the time we are working with `savingsAcct_` and then restore the ownership on `unique_lock`.
|
||||
We need a way to transfer the ownership from the `unique_lock` to a `strict_lock` during the time we are working with `savingsAcct_` and then restore the ownership on `unique_lock`.
|
||||
|
||||
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
|
||||
unique_lock<AccountManager> guard1(*this, defer_lock);
|
||||
@@ -480,9 +480,9 @@ We need a way to transfer the ownership from the `unique_lock` to a `strict_lock
|
||||
guard1.unlock();
|
||||
}
|
||||
|
||||
In order to make this code compilable we need to store either a Lockable or a `unique_lock<Lockable>` reference depending on the constructor. Store which kind of reference we have stored,and in the destructor call either to the Lockable `unlock` or restore the ownership.
|
||||
In order to make this code compilable we need to store either a Lockable or a `unique_lock<Lockable>` reference depending on the constructor. We also need to store which kind of reference we have stored, and in the destructor call either to the Lockable `unlock` or restore the ownership.
|
||||
|
||||
This seams too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict_lock` or make these function templates functions. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that check that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to belive it "sur parole". The advantage is that now we can manage with more than two strict locks without changing our code. This is really nice.
|
||||
This seems too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict_lock` or make these function templates. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that checks that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to believe it "sur parole". The advantage is that now we can manage with more than two strict locks without changing our code. This is really nice.
|
||||
|
||||
Now we need to state that both classes are `strict_lock`s.
|
||||
|
||||
@@ -496,9 +496,9 @@ Now we need to state that both classes are `strict_lock`s.
|
||||
struct is_strict_lock<nested_strict_lock<Locker> > : mpl::true_ {}
|
||||
|
||||
|
||||
Well let me show how this `nested_strict_lock` class looks like and the impacts on the `externally_locked` class and the `AccountManager::AMoreComplicatedFunction` function.
|
||||
Well let me show what this `nested_strict_lock` class looks like and the impacts on the `externally_locked` class and the `AccountManager::AMoreComplicatedFunction` function.
|
||||
|
||||
First `nested_strict_lock` class will store on a temporary lock the `Locker`, and transfer the lock ownership on the constructor. On destruction he will restore the ownership. Note also that the Locker needs to have already a reference to the mutex otherwise an exception is thrown and the use of the `lock_traits`.
|
||||
First `nested_strict_lock` class will store on a temporary lock the `Locker`, and transfer the lock ownership on the constructor. On destruction it will restore the ownership. Note the use of `lock_traits` and that the `Locker` needs to have a reference to the mutex otherwise and exception is thrown.
|
||||
|
||||
template <typename Locker >
|
||||
class nested_strict_lock
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
[///////////////////////////////////]
|
||||
[section:reference Futures Reference]
|
||||
|
||||
//#include <boost/thread/futures.hpp>
|
||||
//#include <boost/thread/future.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -30,6 +30,7 @@
|
||||
{
|
||||
async = unspecified,
|
||||
deferred = unspecified,
|
||||
executor = unspecified,
|
||||
any = async | deferred
|
||||
};
|
||||
|
||||
@@ -51,6 +52,8 @@
|
||||
|
||||
class future_error;
|
||||
|
||||
class exceptional_ptr;
|
||||
|
||||
template <typename R>
|
||||
class promise;
|
||||
|
||||
@@ -88,6 +91,9 @@
|
||||
template <class F, class... Args>
|
||||
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(launch policy, F&& f, Args&&... args);
|
||||
template <class Executor, class F, class... Args>
|
||||
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(Executor &ex, F&& f, Args&&... args);
|
||||
|
||||
template<typename Iterator>
|
||||
void wait_for_all(Iterator begin,Iterator end); // EXTENSION
|
||||
@@ -106,10 +112,16 @@
|
||||
template <typename T>
|
||||
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
|
||||
future<void> make_ready_future(); // EXTENSION
|
||||
template <typename T>
|
||||
future<T> make_ready_future(exception_ptr ex); // EXTENSION
|
||||
template <typename T, typename E>
|
||||
future<T> make_ready_future(E ex); // EXTENSION
|
||||
//template <typename T>
|
||||
//future<T> make_ready_future(exception_ptr ex); // DEPRECATED
|
||||
//template <typename T, typename E>
|
||||
//future<T> make_ready_future(E ex); // DEPRECATED
|
||||
|
||||
exceptional_ptr make_exceptional(exception_ptr ex); // EXTENSION
|
||||
template <typename E>
|
||||
exceptional_ptr make_exceptional(E ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional(); // EXTENSION
|
||||
|
||||
|
||||
template <typename T>
|
||||
shared_future<typename decay<T>::type> make_shared_future(T&& value); // DEPRECATED
|
||||
@@ -147,6 +159,7 @@
|
||||
{
|
||||
async = unspecified,
|
||||
deferred = unspecified,
|
||||
executor = unspecified,
|
||||
any = async | deferred
|
||||
};
|
||||
|
||||
@@ -260,6 +273,42 @@ The object's `name` virtual function returns a pointer to the string "future".]]
|
||||
};
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////////]
|
||||
[section:future_error Class `exceptional_ptr` EXPERIMENTAL]
|
||||
|
||||
class exceptional_ptr
|
||||
{
|
||||
public:
|
||||
exceptional_ptr();
|
||||
explicit exceptional_ptr(exception_ptr ex);
|
||||
template <class E>
|
||||
explicit exceptional_ptr(E&& ex);
|
||||
};
|
||||
|
||||
[///////////////////////////////]
|
||||
[section:constructor Constructor]
|
||||
|
||||
exceptional_ptr();
|
||||
explicit exceptional_ptr(exception_ptr ex);
|
||||
template <class E>
|
||||
explicit exceptional_ptr(E&& ex);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The exception that is passed in to the constructor or the current exception if no parameter is moved into the constructed `exceptional_ptr` if it is an rvalue. Otherwise the exception is copied into the constructed `exceptional_ptr`.]]
|
||||
|
||||
[[Postconditions:] [
|
||||
`valid() == true && is_ready() = true && has_value() = false`
|
||||
]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
|
||||
[////////////////////////////////////////////////////]
|
||||
[section:unique_future __unique_future class template]
|
||||
|
||||
@@ -557,8 +606,6 @@ associated with `*this` is not ready at the point of the call, and the current t
|
||||
[warning
|
||||
DEPRECATED since 3.00.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use instead __wait_for.
|
||||
]
|
||||
|
||||
@@ -595,8 +642,6 @@ elapsed, `false` otherwise.]]
|
||||
[warning
|
||||
DEPRECATED since 3.00.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use instead __wait_until.
|
||||
]
|
||||
|
||||
@@ -1892,7 +1937,9 @@ provides the result of the function in a future object with which it shares a sh
|
||||
template <class F>
|
||||
__unique_future__<typename result_of<typename decay<F>::type()>::type>
|
||||
async(launch policy, F&& f);
|
||||
|
||||
template <class Executor, class F>
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(Executor &ex, F&& f, Args&&... args);
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [
|
||||
@@ -1957,7 +2004,10 @@ If the implementation chooses the `launch::async` policy,
|
||||
template <class F, class... Args>
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(launch policy, F&& f, Args&&... args);
|
||||
|
||||
template <class Executor, class F, class... Args>
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(Executor &ex, F&& f, Args&&... args);
|
||||
|
||||
[warning the variadic prototype is provided only on C++11 compilers supporting rvalue references, variadic templates, decltype and a standard library providing <tuple> (waiting for a boost::tuple that is move aware), and BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK is defined.]
|
||||
|
||||
[variablelist
|
||||
@@ -2115,9 +2165,9 @@ __unique_future__ or __shared_future__.]]
|
||||
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
|
||||
future<void> make_ready_future(); // EXTENSION
|
||||
template <typename T>
|
||||
future<T> make_ready_future(exception_ptr ex); // EXTENSION
|
||||
future<T> make_ready_future(exception_ptr ex); // DEPRECATED
|
||||
template <typename T, typename E>
|
||||
future<T> make_ready_future(E ex); // EXTENSION
|
||||
future<T> make_ready_future(E ex); // DEPRECATED
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -2152,6 +2202,28 @@ Otherwise the value is copied to the shared state of the returned function.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////////////////////////////////////////////]
|
||||
[section:make_exceptional Non-member function `make_exceptional()` EXTENSION]
|
||||
|
||||
exceptional_ptr make_exceptional(exception_ptr ex); // EXTENSION
|
||||
template <typename E>
|
||||
exceptional_ptr make_exceptional(E ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional(); // EXTENSION
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [
|
||||
The exception that is passed in to the function or the current exception if no parameter is given is moved into the returned `exceptional_ptr` if it is an rvalue. Otherwise the exception is copied into the returned `exceptional_ptr`.
|
||||
]]
|
||||
|
||||
[[Returns:] [
|
||||
An exceptional_ptr instance implicitly convertible to a future<T>
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[//////////////////////////////////////////////////////////////////]
|
||||
[section:make_future Non-member function `make_future()` DEPRECATED]
|
||||
|
||||
|
||||
@@ -308,7 +308,7 @@ The second `get()` call in the following example is undefined.
|
||||
use3( ftr.get() ); // second use is undefined
|
||||
}
|
||||
|
||||
Using a `shared_mutex` solves the issue
|
||||
Using a `shared_future` solves the issue
|
||||
|
||||
void good_second_use( type arg ) {
|
||||
|
||||
@@ -341,7 +341,7 @@ Here `share()` could be used to simplify the code
|
||||
use3( ftr.get() ); // second use is defined
|
||||
}
|
||||
|
||||
[heading Writting on get()]
|
||||
[heading Writing on get()]
|
||||
|
||||
The user can either read or write the future avariable.
|
||||
|
||||
@@ -412,7 +412,7 @@ or wasting threads on polling, greatly improving the responsiveness and scalabil
|
||||
With `.then()` the antecedent future is ready (has a value or exception stored in the shared state) before the continuation
|
||||
starts as instructed by the lambda function.
|
||||
|
||||
In the example below the `future<int>` `f2` is registered to be a continuation of `future<int>` `f1` using the `.then()` member
|
||||
In the example below the `future<string>` `f2` is registered to be a continuation of `future<int>` `f1` using the `.then()` member
|
||||
function. This operation takes a lambda function which describes how `f2` should proceed after `f1` is ready.
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[/
|
||||
/ Copyright (c) 2008 Vicente J. Botet Escriba
|
||||
/ Copyright (c) 2008,2014 Vicente J. Botet Escriba
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -14,7 +14,7 @@ Consider, for example, modeling a bank account class that supports simultaneous
|
||||
|
||||
From here a component is a model of the `Callable` concept.
|
||||
|
||||
On C++11 (Boost) concurrent execution of a component is obtained by means of the `std::thread`(`boost::thread`):
|
||||
I C++11 (Boost) concurrent execution of a component is obtained by means of the `std::thread`(`boost::thread`):
|
||||
|
||||
boost::thread thread1(S);
|
||||
|
||||
@@ -53,12 +53,12 @@ The following example includes a bank account of a person (Joe) and two componen
|
||||
return 0;
|
||||
}
|
||||
|
||||
From time to time, the `bankAgent` will deposit $500 in `JoesAccount`. Joe will similarly withdraw $100 from his account. These sentences describe that the bankAgent and Joe are executed concurrently.
|
||||
From time to time, the `bankAgent` will deposit $500 in `JoesAccount`. `Joe` will similarly withdraw $100 from his account. These sentences describe that the `bankAgent` and `Joe` are executed concurrently.
|
||||
|
||||
[endsect]
|
||||
[section Internal locking]
|
||||
|
||||
The above example works well as long as the bankAgent and Joe doesn't access JoesAccount at the same time. There is, however, no guarantee that this will not happen. We may use a mutex to guarantee exclusive access to each bank.
|
||||
The above example works well as long as the components `bankAgent` and `Joe` doesn't access `JoesAccount` at the same time. There is, however, no guarantee that this will not happen. We may use a mutex to guarantee exclusive access to each bank.
|
||||
|
||||
class BankAccount {
|
||||
boost::mutex mtx_;
|
||||
@@ -82,11 +82,11 @@ The above example works well as long as the bankAgent and Joe doesn't access Joe
|
||||
}
|
||||
};
|
||||
|
||||
Execution of the Deposit and Withdraw operations will no longer be able to make simultaneous access to balance.
|
||||
Execution of the `Deposit` and `Withdraw` operations will no longer be able to make simultaneous access to balance.
|
||||
|
||||
Mutex is a simple and basic mechanism for obtaining synchronization. In the above example it is relatively easy to be convinced that the synchronization works correctly (in the absence of exception). In a system with several concurrent objects and several shared objects, it may be difficult to describe synchronization by means of mutexes. Programs that make heavy use of mutexes may be difficult to read and write. Instead, we shall introduce a number of generic classes for handling more complicated forms of synchronization and communication.
|
||||
A mutex is a simple and basic mechanism for obtaining synchronization. In the above example it is relatively easy to be convinced that the synchronization works correctly (in the absence of exception). In a system with several concurrent objects and several shared objects, it may be difficult to describe synchronization by means of mutexes. Programs that make heavy use of mutexes may be difficult to read and write. Instead, we shall introduce a number of generic classes for handling more complicated forms of synchronization and communication.
|
||||
|
||||
With the RAII idiom we can simplify a lot this using the scoped locks. In the code below, guard's constructor locks the passed-in object this, and guard's destructor unlocks this.
|
||||
With the RAII idiom we can simplify a lot this using the scoped locks. In the code below, guard's constructor locks the passed-in object `mtx_`, and guard's destructor unlocks `mtx_`.
|
||||
|
||||
class BankAccount {
|
||||
boost::mutex mtx_; // explicit mutex declaration
|
||||
@@ -135,10 +135,10 @@ In an attempt to solve this problem, let's lock the account from the outside dur
|
||||
acct.Withdraw(2);
|
||||
}
|
||||
|
||||
Notice that the code above doesn't compiles, the `mtx_` field is private.
|
||||
Notice that the code above doesn't compile, the `mtx_` field is private.
|
||||
We have two possibilities:
|
||||
|
||||
* make `mtx_` public which seams odd
|
||||
* make `mtx_` public which seems odd
|
||||
* make the `BankAccount` lockable by adding the lock/unlock functions
|
||||
|
||||
We can add these functions explicitly
|
||||
|
||||
@@ -298,8 +298,6 @@ reached. If the specified time has already passed, behaves as __try_lock_ref__.]
|
||||
[warning
|
||||
DEPRECATED since 4.00. The following expressions were required on version 2, but are now deprecated.
|
||||
|
||||
Available only up to Boost 1.58.
|
||||
|
||||
Use instead __try_lock_for, __try_lock_until.
|
||||
]
|
||||
|
||||
@@ -460,8 +458,6 @@ ownership of `m`.]]
|
||||
[warning
|
||||
DEPRECATED since 3.00. The following expressions were required on version 2, but are now deprecated.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use instead __try_lock_shared_for, __try_lock_shared_until.
|
||||
]
|
||||
|
||||
@@ -1119,6 +1115,44 @@ object passed to the constructor.]]
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:with_lock_guard With Lock Guard]
|
||||
|
||||
// #include <boost/thread/with_lock_guard.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class Lockable, class Function, class... Args>
|
||||
auto with_lock_guard(Lockable& m, Function&& func, Args&&... args) -> decltype(func(boost::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
[section:with_lock_guard Non Member Function `with_lock_guard`]
|
||||
|
||||
template <class Lockable, class Function, class... Args>
|
||||
auto with_lock_guard(
|
||||
Lockable& m,
|
||||
Function&& func,
|
||||
Args&&... args
|
||||
) -> decltype(func(boost::forward<Args>(args)...));
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [`m` must be in unlocked state]]
|
||||
[[Effects:] [call `func` in scope locked by `m`]]
|
||||
[[Returns:] [Result of `func(args...)` call]]
|
||||
[[Throws:] [Any exception thrown by the call to `m.lock` and `func(args...)`]]
|
||||
[[Postcondition:] [`m` is in unlocked state]]
|
||||
|
||||
[[Limitations:] [Without c++11 variadic templates support number of arguments is limited to `4`]]
|
||||
[[] [Without rvalue references support calling class method with `boost::bind` must be const]]
|
||||
[[] [For correct work with lambda macro `BOOST_RESULT_OF_USE_DECLTYPE` may be needed to define]]
|
||||
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -34,9 +34,10 @@ Scoped Threads are wrappers around a thread that allows the user to state what t
|
||||
|
||||
The difference between strict_scoped_thread and scoped_thread is that the strict_scoped_thread hides completely the owned thread and so the user can do nothing with the owned thread other than the specific action given as parameter, while scoped_thread provide the same interface than __thread and forwards all the operations.
|
||||
|
||||
boost::strict_scoped_thread<> t1((boost::thread(F)));
|
||||
boost::strict_scoped_thread<> t2((boost::thread(F)));
|
||||
t2.interrupt();
|
||||
boost::strict_scoped_thread<> t1((boost::thread(f)));
|
||||
//t1.detach(); // compile fails
|
||||
boost::scoped_thread<> t2((boost::thread(f)));
|
||||
t2.detach();
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -216,6 +217,7 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency() noexcept;
|
||||
static unsigned physical_concurrency() noexcept;
|
||||
|
||||
typedef thread::native_handle_type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
@@ -458,6 +460,20 @@ any) to `*this`.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:physical_concurrency Static member function `physical_concurrency()`]
|
||||
|
||||
unsigned physical_concurrency() noexecpt;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to return `thread::physical_concurrency()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef thread::native_handle_type native_handle_type;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
/]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:synchronized_queues Synchronized Queues -- EXPERIMENTAL]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
@@ -12,6 +13,18 @@
|
||||
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3533.html [*N3533 - C++ Concurrent Queues]] C++1y proposal from Lawrence Crowl and Chris Mysen and [@http://www.manning.com/williams/ [*C++ Concurrency in Action]] from Anthony Williams.]
|
||||
|
||||
|
||||
[////////////////////]
|
||||
[section Introduction]
|
||||
|
||||
Queues provide a mechanism for communicating data between components of a system.
|
||||
|
||||
The existing deque in the standard library is an inherently sequential data structure. Its reference-returning element access operations cannot synchronize access to those elements with other queue operations. So, concurrent pushes and pops on queues require a different interface to the queue structure.
|
||||
|
||||
Moreover, concurrency adds a new dimension for performance and semantics. Different queue implementation must trade off uncontended operation cost, contended operation cost, and element order guarantees. Some of these trade-offs will necessarily result in semantics weaker than a serial queue.
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
Concurrent queues are a well know mechanism for communicating data between different threads.
|
||||
@@ -19,7 +32,13 @@ Concurrent queues are a well know mechanism for communicating data between diffe
|
||||
Concurrent queues have inherently copy/move semantics for the data handling operation. Reference-returning interfaces are forbidden as multiple access to these references can not be thread-safe.
|
||||
|
||||
[endsect]
|
||||
[////////////////]
|
||||
[section Examples]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:ref Reference]
|
||||
|
||||
[section:sync_queue_req Synchronized Queue Model]
|
||||
@@ -37,16 +56,15 @@ Locking queues can by nature block waiting for the queue to be non-empty or non-
|
||||
Lock-free queues will have some trouble waiting for the queue to be non-empty or non-full queues. These queues can not define operations such as push (and pull for bounded queues). That is, it could have blocking operations (presumably emulated with busy wait) but not waiting operations.
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:closed Closed Queue]
|
||||
|
||||
Threads using a queue for communication need some mechanism to signal when the queue is no longer needed. The usual approach is add an additional out-of-band signal. However, this approach suffers from the flaw that threads waiting on either full or empty queues need to be woken up when the queue is no longer needed. Rather than require an out-of-band signal, we chose to directly support such a signal in the queue itself, which considerably simplifies coding.
|
||||
|
||||
To achieve this signal, a thread may close a queue. Once closed, no new elements may be pushed onto the queue. Push operations on a closed queue will either return queue_op_status::closed (when they have a queue_op_status return type), set the closed parameter if it has one or throw sync_queue::closed (when they do not). Elements already on the queue may be pulled off. When a queue is empty and closed, pull operations will either return queue_op_status::closed (when they have a status return), set the closed parameter if it has one or throw sync_queue::closed (when they do not).
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:exception Concurrent Queues Throw specification]
|
||||
[section:locking Locking]
|
||||
|
||||
@@ -57,6 +75,7 @@ All the functions are defined as if we had in addition to its specific Throw spe
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:bad_alloc Allocation]
|
||||
|
||||
All the functions that allocate a resource are defined as if we had in addition to its specific Throw specification the following:
|
||||
@@ -67,7 +86,7 @@ All the functions that allocate a resource are defined as if we had in addition
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:BasicConcurrentQueue Basic Concurrent Queue Operations]
|
||||
|
||||
The essential solution to the problem of concurrent queuing is to shift to value-based operations, rather than reference-based operations.
|
||||
@@ -78,11 +97,11 @@ A type `Q` meets the BasicConcurrentQueue requirements if the following expressi
|
||||
|
||||
* Q::value_type
|
||||
* Q::size_type
|
||||
* `q.push(e);`
|
||||
* `q.push(rve);`
|
||||
* `q.pull(lre);`
|
||||
* `lre = q.pull();`
|
||||
* `spe = q.ptr_pull();`
|
||||
* `q.push_back(e);`
|
||||
* `q.push_back(rve);`
|
||||
* `q.pull_front(lre);`
|
||||
* `lre = q.pull_front();`
|
||||
[/* `spe = q.ptr_pull_front();`]
|
||||
* `b = q.empty();`
|
||||
* `u = q.size();`
|
||||
|
||||
@@ -93,14 +112,16 @@ where
|
||||
* `u` denotes a value of type Q::size_type,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `spe` denotes a shared_ptr<Q::value_type>
|
||||
[/* `spe` denotes a shared_ptr<Q::value_type>]
|
||||
* `qs` denotes a variable of of type `queus_op_status`,
|
||||
|
||||
|
||||
[section:push `q.push(e);`]
|
||||
[/////////////////////////////////////]
|
||||
[section:push_back `q.push_back(e);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue copying it (this could need an allocation for unbounded queues).]]
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push back `e` to the queue copying it (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
@@ -115,11 +136,12 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:push_m `q.push(rve);`]
|
||||
[/////////////////////////////////////]
|
||||
[section:push_back_m `q.push_back(rve);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue moving it (this could need an allocation for unbounded queues).]]
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue moving it back in the queue (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
@@ -134,13 +156,12 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:pull_lv `q.pull(lve)`]
|
||||
[/////////////////////////////////////]
|
||||
[section:pull_front_lv `q.pull_front(lve)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
[[Effects:] [Waits until the queue is not empty and then pull_front the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
@@ -155,8 +176,8 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:pull `e = q.pull()`]
|
||||
[/////////////////////////////////////]
|
||||
[section:pull_front `e = q.pull_front()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -179,8 +200,9 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:ptr_pull `spe = q.ptr_pull()`]
|
||||
[/
|
||||
[/////////////////////////////////////]
|
||||
[section:ptr_pull_front `spe = q.ptr_pull_front()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -203,11 +225,10 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
]
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:non_waaiting Non-waiting Concurrent Queue Operations]
|
||||
|
||||
The ConcurrentQueue concept models a queue with .
|
||||
@@ -215,33 +236,42 @@ The ConcurrentQueue concept models a queue with .
|
||||
|
||||
A type `Q` meets the ConcurrentQueue requirements if the following expressions are well-formed and have the specified semantics
|
||||
|
||||
* `b = q.try_push(e);`
|
||||
* `b = q.try_push(rve);`
|
||||
* `b = q.try_pull(lre);`
|
||||
* `s = q.try_push_back(e);`
|
||||
* `s = q.try_push_back(rve);`
|
||||
* `s = q.try_pull_front(lre);`
|
||||
|
||||
where
|
||||
|
||||
* `q` denotes a value of type `Q`,
|
||||
* `e` denotes a value of type Q::value_type,
|
||||
* `u` denotes a value of type Q::size_type,
|
||||
* `e` denotes a value of type `Q::value_type`,
|
||||
* `s` denotes a value of type `queue_status`,
|
||||
* `u` denotes a value of type `Q::size_type`,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `spe` denotes a shared_ptr<Q::value_type>
|
||||
[/* `spe` denotes a shared_ptr<Q::value_type>]
|
||||
|
||||
|
||||
[section:try_push `q.try_push(e);`]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_push_back `s = q.try_push_back(e);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If the queue `q` is not full, push the `e` to the queue copying it.]]
|
||||
[[Effects:] [If the queue `q` is not full and not closed, push back the `e` to the queue copying it.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation when the operation succeeds. ]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
|
||||
[[Return:] [
|
||||
|
||||
[[Postcondition:] [If the call returns `true`, `! q.empty()`.]]
|
||||
- If the queue is closed, returns `queue_op_status::closed`,
|
||||
|
||||
- otherwise if the queue `q` is full return `queue_op_status::full`,
|
||||
|
||||
- otherwise return `queue_op_status::success`;
|
||||
]]
|
||||
|
||||
[[Postcondition:] [If the call returns `queue_op_status::success`, `! q.empty()`.]]
|
||||
|
||||
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
|
||||
|
||||
@@ -250,28 +280,37 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:try_push_m `q.try_push(rve());`]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_push_back_m `s = q.try_push_back(rve());`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If the queue `q` is not full, push the `e` onto the queue moving it.]]
|
||||
[[Effects:] [If the queue `q` is not full and not closed, push back the `e` onto the queue moving it.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
|
||||
[[Return:] [
|
||||
|
||||
[[Postcondition:] [If the call returns `true`, `! q.empty()`.]]
|
||||
- If the queue is closed, returns `queue_op_status::closed`,
|
||||
|
||||
- otherwise if the queue `q` is full return `queue_op_status::full`,
|
||||
|
||||
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
|
||||
- otherwise return `queue_op_status::success`;
|
||||
]]
|
||||
|
||||
[[Postcondition:] [If the call returns `queue_op_status::success`, `! q.empty()`.]]
|
||||
|
||||
[[Throws:] [ Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:pull_lv `b = q.try_pull(lve)`]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_pull_front_lv `s = q.try_pull_front(lve)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -283,7 +322,13 @@ where
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
|
||||
[[Return:] [
|
||||
|
||||
- If the queue `q` is empty return `queue_op_status::empty`,
|
||||
|
||||
- otherwise return `queue_op_status::success`;
|
||||
|
||||
]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the move of `e`.]]
|
||||
|
||||
@@ -293,30 +338,120 @@ where
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:non_blocking Non-blocking Concurrent Queue Operations]
|
||||
|
||||
For cases when blocking for mutual exclusion is undesirable, we have non-blocking operations. The interface is the same as the try operations but is allowed to also return queue_op_status::busy in case the operation is unable to complete without blocking.
|
||||
For cases when blocking for mutual exclusion is undesirable, we have non-blocking operations.
|
||||
The interface is the same as the try operations but is allowed to also return queue_op_status::busy
|
||||
in case the operation is unable to complete without blocking.
|
||||
|
||||
Non-blocking operations are provided only for BlockingQueues
|
||||
|
||||
* `b = q.try_push(nb, e);`
|
||||
* `b = q.try_push(nb, rve);`
|
||||
* `b = q.try_pull(nb, lre);`
|
||||
* `s = q.nonblocking_push_back(nb, e);`
|
||||
* `s = q.nonblocking_push_back(nb, rve);`
|
||||
* `s = q.nonblocking_pull_front(nb, lre);`
|
||||
|
||||
|
||||
where
|
||||
|
||||
* `q` denotes a value of type `Q`,
|
||||
* `e` denotes a value of type Q::value_type,
|
||||
* `u` denotes a value of type Q::size_type,
|
||||
* `s` denotes a value of type `queue_status`,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `spe` denotes a shared_ptr<Q::value_type>
|
||||
[/* `spe` denotes a shared_ptr<Q::value_type>]
|
||||
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:nonblocking_push_back `s = q.nonblocking_push_back(e);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If the queue `q` is not full and not closed, push back the `e` to the queue copying it.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation when the operation succeeds. ]]
|
||||
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the operation would block, return queue_op_status::busy,
|
||||
|
||||
- otherwise, if the queue is closed, return `queue_op_status::closed`,
|
||||
|
||||
- otherwise, if the queue `q` is full return `queue_op_status::full`,
|
||||
|
||||
- otherwise return `queue_op_status::success`;]]
|
||||
|
||||
[[Postcondition:] [If the call returns `queue_op_status::success`, `! q.empty()`.]]
|
||||
|
||||
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:nonblocking_push_back_m `s = q.nonblocking_push_back(rve());`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If the queue `q` is not full and not closed, push back the `e` onto the queue moving it.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the operation would block, return queue_op_status::busy,
|
||||
|
||||
- otherwise if the queue is closed, returns `queue_op_status::closed`,
|
||||
|
||||
- otherwise if the queue `q` is full return `queue_op_status::full`,
|
||||
|
||||
- otherwise return `queue_op_status::success`;]]
|
||||
|
||||
[[Postcondition:] [If the call returns `queue_op_status::success`, `! q.empty()`.]]
|
||||
|
||||
[[Throws:] [ Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:nonblocking_pull_front_lv `s = q.nonblocking_pull_front(lve)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.full()`.]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the operation would block, return queue_op_status::busy,
|
||||
|
||||
- otherwise if the queue `q` is empty return `queue_op_status::empty`,
|
||||
|
||||
- otherwise return `queue_op_status::success`;]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the move of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:bounded Bounded Concurrent Queue Operations]
|
||||
|
||||
Bounded queues add the following valid expressions
|
||||
@@ -325,38 +460,164 @@ Bounded queues add the following valid expressions
|
||||
* `b = q.full();`
|
||||
* `u = q.capacity();`
|
||||
|
||||
|
||||
where
|
||||
|
||||
* `q` denotes a value of type `Q`,
|
||||
* `b` denotes a value of type `bool`,
|
||||
* `u` denotes a value of type `Q::size_type`,
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:full `b = q.full();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [Return `true` iff the queue is full.]]
|
||||
|
||||
[[Remark:] [Not all queues will have a full state, and these would always return false if the function is provided.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:capacity `b = q.capacity();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return type:] [`Q::size_type`.]]
|
||||
|
||||
[[Return:] [Return the capacity of queue.]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:closed_op Closed Concurrent Queue Operations]
|
||||
|
||||
Closed queues add the following valid expressions
|
||||
|
||||
* `q.close();`
|
||||
* `b = q.closed();`
|
||||
|
||||
Basic expressions
|
||||
* `s = q.wait_push_back(e);`
|
||||
* `s = q.wait_push_back(rve);`
|
||||
* `s = q.wait_pull_front(lre);`
|
||||
|
||||
* `q.push(e,c);`
|
||||
* `q.push(rve,c);`
|
||||
* `q.pull(lre,c);`
|
||||
* `spe = q.ptr_pull(c);`
|
||||
[/////////////////////////////////////]
|
||||
[section:wait_push_back `q.close();`]
|
||||
|
||||
Non-waiting operations
|
||||
[variablelist
|
||||
|
||||
* `b = q.try_push(e, c);`
|
||||
* `b = q.try_push(rve, c);`
|
||||
* `b = q.try_pull(lre, c);`
|
||||
[[Effects:] [Close the queue.]]
|
||||
|
||||
Non-blocking operations are provided by BlockingQueues
|
||||
]
|
||||
|
||||
* `b = q.try_push(nb, e, c);`
|
||||
* `b = q.try_push(nb, rve, c);`
|
||||
* `b = q.try_pull(nb, lre, c);`
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:wait_push_back `b = q.closed();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [Return `true` iff the queue is closed.]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:wait_push_back `s = q.wait_push_back(e);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push back `e` to the queue copying it (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.empty()`.]]
|
||||
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the queue is closed retun `queue_op_status::closed`,
|
||||
|
||||
- otherwise, return `queue_op_status::success` if no exception is thrown.
|
||||
|
||||
]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:wait_push_back_m `s = q.wait_push_back(rve);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue moving it back in the queue (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.empty()`.]]
|
||||
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the queue is closed return `queue_op_status::closed`,
|
||||
|
||||
- otherwise, return `queue_op_status::success` if no exception is thrown.
|
||||
|
||||
.]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:wait_pull_front_lv `s = q.wait_pull_front(lve)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [if the queue is not empty and not closed, waits until the queue is not empty and then pull_front the element from the queue `q` and moves the pulled element into `lve`.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.full()`.]]
|
||||
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the queue is empty and closed, return `queue_op_status::closed`,
|
||||
|
||||
- otherwise, return `queue_op_status::success` if no exception is thrown.
|
||||
]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the move of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:sync_bounded_queue_ref Synchronized Bounded Queue]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
@@ -377,6 +638,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem);
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:sync_queue_is_closed Class `sync_queue_is_closed`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
@@ -387,7 +649,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:sync_bounded_queue Class template `sync_bounded_queue<>`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
@@ -415,27 +677,61 @@ Non-blocking operations are provided by BlockingQueues
|
||||
bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void push(const value_type& x);
|
||||
void push(value_type&& x);
|
||||
bool try_push(const value_type& x);
|
||||
bool try_push(value_type&& x);
|
||||
bool try_push(no_block_tag, const value_type& x);
|
||||
bool try_push(no_block_tag, value_type&& x);
|
||||
void push_back(const value_type& x);
|
||||
void push_back(value_type&& x);
|
||||
|
||||
queue_op_status try_push_back(const value_type& x);
|
||||
queue_op_status try_push_back(value_type&&) x);
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x);
|
||||
queue_op_status nonblocking_push_back(value_type&& x);
|
||||
|
||||
void pull_front(value_type&);
|
||||
value_type pull_front();
|
||||
|
||||
queue_op_status try_pull_front(value_type&);
|
||||
queue_op_status nonblocking_pull_front(value_type&);
|
||||
|
||||
void pull(value_type&);
|
||||
// enable_if is_nothrow_movable<value_type>
|
||||
value_type pull();
|
||||
shared_ptr<ValueType> ptr_pull();
|
||||
bool try_pull(value_type&);
|
||||
bool try_pull(no_block_tag,value_type&);
|
||||
shared_ptr<ValueType> try_pull();
|
||||
|
||||
void close();
|
||||
};
|
||||
}
|
||||
|
||||
[/ shared_ptr<ValueType> ptr_pull_front();]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `sync_bounded_queue(size_type)`]
|
||||
|
||||
explicit sync_bounded_queue(size_type max_elems);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a sync_bounded_queue with a maximum number of elements given by `max_elems`. ]]
|
||||
|
||||
[[Throws:] [any exception that can be throw because of resources unavailable. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:constructort Template Constructor `sync_bounded_queue(size_type, Range)`]
|
||||
|
||||
template <typename Range>
|
||||
sync_bounded_queue(size_type max_elems, Range range);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a sync_bounded_queue with a maximum number of elements given by `max_elems` and push back the elements of the range. ]]
|
||||
|
||||
[[Throws:] [any exception that can be throw because of resources unavailable. ]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:stream_out_operators Non-Member Function `operator<<()`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
@@ -448,6 +744,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:stream_in_operators Non-Member Function `operator>>()`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
@@ -460,6 +757,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:sync_queue_ref Synchronized Unbounded Queue]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
@@ -477,6 +775,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem);
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:sync_queue Class template `sync_queue<>`]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
@@ -488,13 +787,14 @@ Non-blocking operations are provided by BlockingQueues
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef csbl::deque<ValueType> underlying_queue_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
sync_queue(sync_queue const&) = delete;
|
||||
sync_queue& operator=(sync_queue const&) = delete;
|
||||
sync_queue();
|
||||
explicit template <typename Range>
|
||||
sync_queue(Range range);
|
||||
sync_queue(Range range); // Not yet implemented
|
||||
~sync_queue();
|
||||
|
||||
// Observers
|
||||
@@ -504,27 +804,89 @@ Non-blocking operations are provided by BlockingQueues
|
||||
bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void push(const value_type& x);
|
||||
void push(value_type&& x);
|
||||
bool try_push(const value_type& x);
|
||||
bool try_push(value_type&&) x);
|
||||
bool try_push(no_block_tag, const value_type& x);
|
||||
bool try_push(no_block_tag, value_type&& x);
|
||||
void push_back(const value_type& x);
|
||||
void push_back(value_type&& x);
|
||||
|
||||
void pull(value_type&);
|
||||
// enable_if is_nothrow_movable<value_type>
|
||||
value_type pull();
|
||||
shared_ptr<ValueType> ptr_pull();
|
||||
bool try_pull(value_type&);
|
||||
bool try_pull(no_block_tag,value_type&);
|
||||
shared_ptr<ValueType> try_pull();
|
||||
queue_op_status try_push_back(const value_type& x);
|
||||
queue_op_status try_push_back(value_type&&) x);
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x);
|
||||
queue_op_status nonblocking_push_back(value_type&& x);
|
||||
|
||||
void pull_front(value_type&);
|
||||
value_type pull_front();
|
||||
|
||||
queue_op_status try_pull_front(value_type&);
|
||||
queue_op_status nonblocking_pull_front(value_type&);
|
||||
|
||||
underlying_queue_type underlying_queue() noexcept;
|
||||
|
||||
void close();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
[/ shared_ptr<ValueType> ptr_pull_front();]
|
||||
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `sync_bounded_queue(size_type)`]
|
||||
|
||||
explicit sync_queue();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an empty sync_queue. ]]
|
||||
|
||||
[[Throws:] [any exception that can be throw because of resources unavailable. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:constructort Template Constructor `sync_bounded_queue(size_type, Range)`]
|
||||
|
||||
template <typename Range>
|
||||
sync_bounded_queue(size_type max_elems, Range range);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an sync_queue with all the elements of the range. ]]
|
||||
|
||||
[[Throws:] [any exception that can be throw because of resources unavailable. ]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:full Member Function `full()`]
|
||||
|
||||
bool full() const;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [false. ]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Member Function `underlying_queue()`]
|
||||
|
||||
underlying_queue_type underlying_queue() noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [Moves internal queue. ]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:stream_out_operators Non-Member Function `operator<<()`]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
@@ -537,6 +899,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:stream_in_operators Non-Member Function `operator>>()`]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
|
||||
@@ -20,24 +20,44 @@ In addition to the C++11 standard locks, Boost.Thread provides other locks and s
|
||||
|
||||
[section:with Executing Around a Function]
|
||||
|
||||
In particular, the library provides some lock factories.
|
||||
In particular, the library provides a way to lock around the execution of a function.
|
||||
|
||||
template <class Lockable, class Function>
|
||||
auto with_lock_guard(Lockable& m, Function f) -> decltype(f())
|
||||
{
|
||||
auto&& _ = boost::make_lock_guard(m);
|
||||
f();
|
||||
template <class Lockable, class Function, class... Args>
|
||||
auto with_lock_guard(
|
||||
Lockable& m,
|
||||
Function&& func,
|
||||
Args&&... args
|
||||
) -> decltype(func(boost::forward<Args>(args)...)) {
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
that can be used with regular functions:
|
||||
|
||||
that can be used as
|
||||
int func(int, int&);
|
||||
//...
|
||||
boost::mutex m;
|
||||
int a;
|
||||
int result = boost::with_lock_guard(m, func, 1, boost::ref(a));
|
||||
|
||||
int i = with_lock_guard(mtx, []()
|
||||
{
|
||||
// access the protected state
|
||||
return true;
|
||||
});
|
||||
with boost::bind:
|
||||
|
||||
int result = boost::with_lock_guard(
|
||||
m, boost::bind(func, 2, boost::ref(a))
|
||||
);
|
||||
|
||||
or with lambda expression:
|
||||
|
||||
int a;
|
||||
int result = boost::with_lock_guard(
|
||||
m,
|
||||
[&a](int x) {
|
||||
// this scope is protected by mutex m
|
||||
a = 3;
|
||||
return x + 4;
|
||||
},
|
||||
5
|
||||
);
|
||||
|
||||
[endsect] [/ With]
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
[library Thread
|
||||
[quickbook 1.5]
|
||||
[version 4.2.0]
|
||||
[version 4.3.0]
|
||||
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
|
||||
[copyright 2007-11 Anthony Williams]
|
||||
[copyright 2011-13 Vicente J. Botet Escriba]
|
||||
[copyright 2011-14 Vicente J. Botet Escriba]
|
||||
[purpose C++ Library for launching threads and synchronizing data between them]
|
||||
[category text]
|
||||
[license
|
||||
@@ -239,9 +239,9 @@
|
||||
[include condition_variables.qbk]
|
||||
[include once.qbk]
|
||||
[include barrier.qbk]
|
||||
[/include latch.qbk]
|
||||
[include latch.qbk]
|
||||
[include async_executors.qbk]
|
||||
[include futures.qbk]
|
||||
[/include async_executors.qbk]
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@
|
||||
|
||||
[section:sds Synchronized Data Structures]
|
||||
[include synchronized_value.qbk]
|
||||
[/include sync_queues_ref.qbk]
|
||||
[include sync_queues_ref.qbk]
|
||||
[/include sync_streams.qbk]
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -470,6 +470,7 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency() noexcept;
|
||||
static unsigned physical_concurrency() noexcept;
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
@@ -532,24 +533,14 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
|
||||
thread& operator=(thread&& other) noexcept;
|
||||
|
||||
|
||||
[warning
|
||||
DEPRECATED since 3.0.0: BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE behavior.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Join the thread before moving.
|
||||
]
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Transfers ownership of the thread managed by `other` (if
|
||||
any) to `*this`.
|
||||
|
||||
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If there was a thread previously associated with `*this` then that thread is detached, DEPRECATED
|
||||
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable call __detach__, DEPRECATED
|
||||
|
||||
- if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to std::terminate.
|
||||
- if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to `std::terminate()`.
|
||||
]]
|
||||
|
||||
[[Postconditions:] [`other->get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the assignment.]]
|
||||
@@ -706,24 +697,17 @@ are copied into internal storage for access by the new thread.]]]
|
||||
|
||||
~thread();
|
||||
|
||||
[warning
|
||||
DEPRECATED since 3.0.0: BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE behavior.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Join the thread before destroying or use a scoped thread.
|
||||
]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [
|
||||
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If `*this` has an associated thread of execution, calls __detach__, DEPRECATED
|
||||
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls __detach__, DEPRECATED
|
||||
|
||||
- BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to std::terminate. Destroys `*this`.]]
|
||||
- if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to `std::terminate`. Destroys `*this`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Note:] [Either implicitly detaching or joining a `joinable()` thread in its destructor could result in difficult to debug correctness (for `detach`) or performance (for `join`) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable.]]
|
||||
[[Note:] [The reason to moving to std::terminate is that either implicitly detaching or joining a `joinable()` thread in its destructor could result in difficult to debug correctness (for `detach`) or performance (for `join`) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable. Join the thread before destroying or use an scoped thread.]]
|
||||
|
||||
]
|
||||
|
||||
@@ -794,8 +778,6 @@ corresponding successful `join()` return. ]]
|
||||
[warning
|
||||
DEPRECATED since 3.00.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use instead __try_join_for, __try_join_until.
|
||||
]
|
||||
|
||||
@@ -991,6 +973,21 @@ or 0 if this information is not available.]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:physical_concurrency Static member function `physical_concurrency()`]
|
||||
|
||||
unsigned physical_concurrency() noexecpt;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [The number of physical cores available on the current system. In contrast to `hardware_concurrency()` it does not return
|
||||
the number of virtual cores, but it counts only physical cores.]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
@@ -1014,8 +1011,6 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
|
||||
[warning
|
||||
DEPRECATED since 4.0.0.
|
||||
|
||||
Available only up to Boost 1.58.
|
||||
|
||||
Use `a.__get_id()==b.__get_id()` instead`.
|
||||
]
|
||||
|
||||
@@ -1036,8 +1031,6 @@ Use `a.__get_id()==b.__get_id()` instead`.
|
||||
[warning
|
||||
DEPRECATED since 4.0.0.
|
||||
|
||||
Available only up to Boost 1.58.
|
||||
|
||||
Use `a.__get_id()!=b.__get_id()` instead`.
|
||||
]
|
||||
|
||||
@@ -1056,8 +1049,6 @@ Use `a.__get_id()!=b.__get_id()` instead`.
|
||||
[warning
|
||||
DEPRECATED since 3.0.0.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use `this_thread::__sleep_for()` or `this_thread::__sleep_until()`.
|
||||
]
|
||||
|
||||
@@ -1081,8 +1072,6 @@ Use `this_thread::__sleep_for()` or `this_thread::__sleep_until()`.
|
||||
[warning
|
||||
DEPRECATED since 3.0.0.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use `this_thread::__yield()`.
|
||||
]
|
||||
|
||||
@@ -1474,8 +1463,6 @@ thread attributes implementation. If no such instance exists, `native_handle()`
|
||||
[warning
|
||||
DEPRECATED since 3.0.0.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use `__sleep_for()` and `__sleep_until()` instead.
|
||||
]
|
||||
|
||||
|
||||
146
example/executor.cpp
Normal file
146
example/executor.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright (C) 2012-2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
|
||||
#include <boost/thread/caller_context.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/executors/loop_executor.hpp>
|
||||
#include <boost/thread/executors/serial_executor.hpp>
|
||||
#include <boost/thread/executors/inline_executor.hpp>
|
||||
#include <boost/thread/executors/thread_executor.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/executors/executor_adaptor.hpp>
|
||||
#include <boost/thread/executor.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
void p1()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
//boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
|
||||
}
|
||||
|
||||
void p2()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
//boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
||||
}
|
||||
|
||||
int f1()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
return 1;
|
||||
}
|
||||
int f2(int i)
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(2));
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
void submit_some(boost::executor& tp)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
tp.submit(&p2);
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
tp.submit(&p1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void at_th_entry(boost::basic_thread_pool& )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::executor_adaptor < boost::basic_thread_pool > ea(4);
|
||||
submit_some( ea);
|
||||
{
|
||||
boost::future<int> t1 = boost::async(ea, &f1);
|
||||
boost::future<int> t2 = boost::async(ea, &f1);
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
// std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
}
|
||||
submit_some(ea);
|
||||
{
|
||||
boost::basic_thread_pool ea3(1);
|
||||
boost::future<int> t1 = boost::async(ea3, &f1);
|
||||
boost::future<int> t2 = boost::async(ea3, &f1);
|
||||
//boost::future<int> t2 = boost::async(ea3, f2, 1); // todo this doesn't compiles yet on C++11
|
||||
//boost::future<int> t2 = boost::async(ea3, boost::bind(f2, 1)); // todo this doesn't compiles yet on C++98
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
// std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
}
|
||||
submit_some(ea);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::loop_executor > ea2;
|
||||
submit_some( ea2);
|
||||
ea2.underlying_executor().run_queued_closures();
|
||||
}
|
||||
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::basic_thread_pool > ea1(4);
|
||||
boost::executor_adaptor < boost::serial_executor > ea2(ea1);
|
||||
submit_some(ea2);
|
||||
}
|
||||
#endif
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::inline_executor > ea1;
|
||||
submit_some(ea1);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::thread_executor > ea1;
|
||||
submit_some(ea1);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::basic_thread_pool ea(4, at_th_entry);
|
||||
boost::future<int> t1 = boost::async(ea, &f1);
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
}
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERROR= " << ex.what() << "" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERROR= exception thrown" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -3,8 +3,16 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
@@ -12,6 +20,7 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
|
||||
@@ -29,39 +38,58 @@ int p1()
|
||||
|
||||
int main()
|
||||
{
|
||||
const int number_of_tests = 100;
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
//boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(&p1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = f1.fallback_to(-1);
|
||||
assert(f2.get()==1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
f2.wait();
|
||||
BOOST_ASSERT(f2.get()==1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1_ex);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = f1.fallback_to(-1);
|
||||
assert(f2.get()==-1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
f2.wait();
|
||||
BOOST_ASSERT(f2.get()==-1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,18 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
//&& ! defined BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
@@ -21,13 +31,14 @@ int p1()
|
||||
|
||||
int p2(boost::future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG << "<P2" << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG << "P2<" << BOOST_THREAD_END_LOG;
|
||||
try
|
||||
{
|
||||
return 2 * f.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
@@ -40,13 +51,14 @@ int p2(boost::future<int> f)
|
||||
}
|
||||
int p2s(boost::shared_future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG << "<P2" << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG << "<P2S" << BOOST_THREAD_END_LOG;
|
||||
try
|
||||
{
|
||||
return 2 * f.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
@@ -55,47 +67,60 @@ int p2s(boost::shared_future<int> f)
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
BOOST_THREAD_LOG << "P2>" << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG << "P2S>" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const int number_of_tests = 100;
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = f1.then(&p2);
|
||||
(void)f2.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(&p1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = f1.then(&p2);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
(void)f2.get();
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::shared_future<int> f1 = boost::async(boost::launch::async, &p1).share();
|
||||
boost::future<int> f2 = f1.then(&p2s);
|
||||
(void)f2.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::shared_future<int> f1 = boost::async(&p1).share();
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = f1.then(&p2s);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
(void)f2.get();
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
|
||||
@@ -3,14 +3,24 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
||||
|
||||
int p1()
|
||||
@@ -29,21 +39,25 @@ boost::future<int> p2()
|
||||
|
||||
int main()
|
||||
{
|
||||
const int number_of_tests = 100;
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
boost::future<boost::future<int> > outer_future = boost::async(boost::launch::async, &p2);
|
||||
boost::future<int> inner_future = outer_future.unwrap();
|
||||
int i = inner_future.get();
|
||||
BOOST_THREAD_LOG << "i= "<< i << "" << BOOST_THREAD_END_LOG;
|
||||
int ii = inner_future.get();
|
||||
BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
|
||||
166
example/future_when_all.cpp
Normal file
166
example/future_when_all.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
// Copyright (C) 2012-2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <string>
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "P1" << BOOST_THREAD_END_LOG;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
return 123;
|
||||
}
|
||||
int p1b()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "P1b" << BOOST_THREAD_END_LOG;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
return 321;
|
||||
}
|
||||
|
||||
int p2(boost::future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " P2 " << BOOST_THREAD_END_LOG;
|
||||
try
|
||||
{
|
||||
return 2 * f.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
BOOST_THREAD_LOG
|
||||
<< "P2>" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
int p2s(boost::shared_future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "<P2" << BOOST_THREAD_END_LOG;
|
||||
try
|
||||
{
|
||||
return 2 * f.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
BOOST_THREAD_LOG
|
||||
<< "P2>" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<std::tuple<> > all0 = boost::when_all();
|
||||
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_all(boost::move(f1), boost::move(f2));
|
||||
//(void) all.wait();
|
||||
boost::csbl::vector<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< res[0].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< res[1].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<std::tuple<> > all0 = boost::when_any();
|
||||
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
//(void) all.wait();
|
||||
boost::csbl::vector<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< res[0].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< res[1].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG
|
||||
<< "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
using namespace boost;
|
||||
|
||||
void f( boost::csbl::vector<future<int> > &//vec
|
||||
, BOOST_THREAD_RV_REF(future<int>) //f
|
||||
) {
|
||||
//vec.push_back(boost::forward<future<int> >(f));
|
||||
}
|
||||
int main()
|
||||
{
|
||||
boost::csbl::vector<future<int> > vec;
|
||||
f(vec, make_ready_future(0));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -8,22 +8,30 @@
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \
|
||||
&& ! defined BOOST_NO_CXX11_LAMBDAS
|
||||
&& ! defined BOOST_NO_CXX11_LAMBDAS && ! (defined BOOST_MSVC && _MSC_VER < 1700)
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
const int number_of_tests = 100;
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
{
|
||||
@@ -40,11 +48,13 @@ int main()
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
@@ -19,6 +24,7 @@ namespace boost
|
||||
}
|
||||
|
||||
int p1() { return 5; }
|
||||
int& p1r() { static int i=0; return i; }
|
||||
|
||||
void p() { }
|
||||
|
||||
@@ -32,41 +38,92 @@ boost::future<void> void_compute()
|
||||
boost::future<int> compute(int x)
|
||||
{
|
||||
if (x == 0) return boost::make_ready_future(0);
|
||||
//if (x < 0) return boost::make_ready_future<int>(boost::make_exception_ptr(std::logic_error("Error")));
|
||||
if (x < 0) return boost::make_ready_future<int>(std::logic_error("Error"));
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
if (x < 0) return boost::make_exceptional_future<int>(std::logic_error("Error"));
|
||||
#else
|
||||
if (x < 0) return boost::make_exceptional(std::logic_error("Error"));
|
||||
#endif
|
||||
//boost::future<int> f1 = boost::async([]() { return x+1; });
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, p1);
|
||||
boost::future<int> f1 = boost::async(p1);
|
||||
return boost::move(f1);
|
||||
}
|
||||
|
||||
boost::future<int&> compute_ref(int x)
|
||||
{
|
||||
static int i = 0;
|
||||
//if (x == 0) return boost::make_ready_future<int&>(i); //This must not compile as the type is deduced as boost::future<int>
|
||||
if (x == 0) return boost::make_ready_no_decay_future<int&>(i);
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
if (x < 0) return boost::make_exceptional_future<int&>(std::logic_error("Error"));
|
||||
#else
|
||||
if (x < 0) return boost::make_exceptional(std::logic_error("Error"));
|
||||
#endif
|
||||
boost::future<int&> f1 = boost::async(p1r);
|
||||
return boost::move(f1);
|
||||
}
|
||||
|
||||
boost::shared_future<int> shared_compute(int x)
|
||||
{
|
||||
if (x == 0) return boost::make_ready_future(0).share();
|
||||
if (x < 0) return boost::make_ready_future<int>(std::logic_error("Error")).share();
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
if (x < 0) return boost::make_exceptional_future<int>(std::logic_error("Error")).share();
|
||||
#else
|
||||
if (x < 0) return boost::make_exceptional(std::logic_error("Error"));
|
||||
#endif
|
||||
//boost::future<int> f1 = boost::async([]() { return x+1; });
|
||||
boost::shared_future<int> f1 = boost::async(p1).share();
|
||||
return boost::move(f1);
|
||||
boost::shared_future<int> f1 = boost::async(&p1).share();
|
||||
return f1;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
const int number_of_tests = 100;
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
// {
|
||||
// std::cout << __FILE__ << " "<<__LINE__ << std::endl;
|
||||
// boost::future<int> f = boost::async(boost::launch::async, p1);
|
||||
// std::cout << i << " "<<f.get() << std::endl;
|
||||
// }
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::future<void> f = void_compute();
|
||||
f.get();
|
||||
}
|
||||
#endif
|
||||
{
|
||||
boost::future<int> f = compute(2);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::future<int> f = compute(0);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
{
|
||||
boost::shared_future<int> f = shared_compute(2);
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::future<int&> f = compute_ref(0);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
// {
|
||||
// std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
// boost::future<int> f = compute(2);
|
||||
// std::cout << f.get() << std::endl;
|
||||
// }
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::shared_future<int> f = shared_compute(0);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<"ERRORRRRR exception thrown" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
61
example/not_interleaved2.cpp
Normal file
61
example/not_interleaved2.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// (C) Copyright 2012 Howard Hinnant
|
||||
// (C) Copyright 2012 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <boost/thread/ostream_buffer.hpp>
|
||||
|
||||
void use_cerr()
|
||||
{
|
||||
using namespace boost;
|
||||
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
|
||||
int i = 0;
|
||||
while (chrono::steady_clock::now() < tf)
|
||||
{
|
||||
ostream_buffer<std::ostream> mcerr(std::cerr);
|
||||
mcerr.stream() << "logging data to cerr " << i++ << "\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
|
||||
void use_cout()
|
||||
{
|
||||
using namespace boost;
|
||||
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
|
||||
int i = 0;
|
||||
while (chrono::steady_clock::now() < tf)
|
||||
{
|
||||
ostream_buffer<std::ostream> mcout(std::cout);
|
||||
mcout.stream() << "logging data to cout " << i++ << "\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
scoped_thread<> t1(&use_cerr);
|
||||
scoped_thread<> t2(&use_cout);
|
||||
this_thread::sleep_for(chrono::seconds(2));
|
||||
std::string nm = "he, he\n";
|
||||
{
|
||||
ostream_buffer<std::ostream> mcout(std::cout);
|
||||
mcout.stream() << "Enter name: \n";
|
||||
}
|
||||
t1.join();
|
||||
t2.join();
|
||||
{
|
||||
ostream_buffer<std::ostream> mcout(std::cout);
|
||||
mcout.stream() << nm;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
100
example/parallel_accumulate.cpp
Normal file
100
example/parallel_accumulate.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (C) 2014 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
//#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
|
||||
template<typename Iterator,typename T>
|
||||
struct accumulate_block
|
||||
{
|
||||
//typedef T result_type;
|
||||
T operator()(Iterator first,Iterator last)
|
||||
{
|
||||
return std::accumulate(first,last,T());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Iterator,typename T>
|
||||
T parallel_accumulate(Iterator first,Iterator last,T init)
|
||||
{
|
||||
unsigned long const length=std::distance(first,last);
|
||||
|
||||
if(!length)
|
||||
return init;
|
||||
|
||||
unsigned long const block_size=25;
|
||||
unsigned long const num_blocks=(length+block_size-1)/block_size;
|
||||
|
||||
boost::csbl::vector<boost::future<T> > futures(num_blocks-1);
|
||||
boost::basic_thread_pool pool;
|
||||
|
||||
Iterator block_start=first;
|
||||
for(unsigned long i=0;i<(num_blocks-1);++i)
|
||||
{
|
||||
Iterator block_end=block_start;
|
||||
std::advance(block_end,block_size);
|
||||
futures[i]=boost::async(pool, accumulate_block<Iterator,T>(), block_start, block_end);
|
||||
block_start=block_end;
|
||||
}
|
||||
T last_result=accumulate_block<Iterator,T>()(block_start,last);
|
||||
T result=init;
|
||||
for(unsigned long i=0;i<(num_blocks-1);++i)
|
||||
{
|
||||
result+=futures[i].get();
|
||||
}
|
||||
result += last_result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
const int s = 1001;
|
||||
std::vector<int> vec;
|
||||
vec.reserve(s);
|
||||
for (int i=0; i<s;++i)
|
||||
vec.push_back(1);
|
||||
int r = parallel_accumulate(vec.begin(), vec.end(),0);
|
||||
std::cout << r << std::endl;
|
||||
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERROR= " << ex.what() << "" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERROR= exception thrown" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
///#warning "This compiler doesn't supports variadics"
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
109
example/parallel_quick_sort.cpp
Normal file
109
example/parallel_quick_sort.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright (C) 2012-2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
//#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
//#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
//#endif
|
||||
|
||||
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
template<typename T>
|
||||
struct sorter
|
||||
{
|
||||
boost::basic_thread_pool pool;
|
||||
typedef std::list<T> return_type;
|
||||
|
||||
std::list<T> do_sort(std::list<T> chunk_data)
|
||||
{
|
||||
if(chunk_data.empty())
|
||||
{
|
||||
return chunk_data;
|
||||
}
|
||||
|
||||
std::list<T> result;
|
||||
result.splice(result.begin(),chunk_data, chunk_data.begin());
|
||||
T const& partition_val=*result.begin();
|
||||
|
||||
typename std::list<T>::iterator divide_point=
|
||||
std::partition(chunk_data.begin(), chunk_data.end(), [&](T const& val){return val<partition_val;});
|
||||
|
||||
std::list<T> new_lower_chunk;
|
||||
new_lower_chunk.splice(new_lower_chunk.end(), chunk_data, chunk_data.begin(), divide_point);
|
||||
|
||||
boost::future<std::list<T> > new_lower = boost::async(pool, &sorter::do_sort, this, std::move(new_lower_chunk));
|
||||
//boost::future<std::list<T> > new_lower = boost::async<return_type>(pool, &sorter::do_sort, this, std::move(new_lower_chunk));
|
||||
|
||||
std::list<T> new_higher(do_sort(chunk_data));
|
||||
|
||||
result.splice(result.end(),new_higher);
|
||||
while(!new_lower.is_ready())
|
||||
{
|
||||
pool.schedule_one_or_yield();
|
||||
}
|
||||
|
||||
result.splice(result.begin(),new_lower.get());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
std::list<T> parallel_quick_sort(std::list<T>& input)
|
||||
{
|
||||
if(input.empty())
|
||||
{
|
||||
return input;
|
||||
}
|
||||
sorter<T> s;
|
||||
|
||||
return s.do_sort(input);
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
const int s = 101;
|
||||
std::list<int> lst;
|
||||
for (int i=0; i<s;++i)
|
||||
lst.push_back(100-i);
|
||||
std::list<int> r = parallel_quick_sort(lst);
|
||||
for (std::list<int>::const_iterator it=r.begin(); it != r.end(); ++it)
|
||||
std::cout << *it << std::endl;
|
||||
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERROR= " << ex.what() << "" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERROR= exception thrown" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
//#warning "This compiler doesn't supports variadics and move semantics"
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -7,21 +7,28 @@
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#ifdef XXXX
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
typedef boost::externally_locked_stream<std::ostream> the_ostream;
|
||||
#else
|
||||
typedef std::ostream the_ostream;
|
||||
typedef std::istream the_istream;
|
||||
#endif
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
|
||||
void producer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
void producer(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
//sbq.push(i);
|
||||
sbq << i;
|
||||
mos << "push(" << i << ") "<< sbq.size()<<"\n";
|
||||
sbq.push_back(i);
|
||||
//sbq << i;
|
||||
mos << "push_back(" << i << ") "<< sbq.size()<<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
@@ -35,16 +42,19 @@ void producer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_qu
|
||||
}
|
||||
}
|
||||
|
||||
void consumer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
void consumer(
|
||||
the_ostream &mos,
|
||||
boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
//sbq.pull(r);
|
||||
sbq >> r;
|
||||
sbq.pull_front(r);
|
||||
//sbq >> r;
|
||||
mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
@@ -57,17 +67,18 @@ void consumer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_qu
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
void consumer2(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
bool closed=false;
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
sbq.pull(r, closed);
|
||||
if (closed) break;
|
||||
mos << i << " pull(" << r << ")\n";
|
||||
queue_op_status st = sbq.try_pull_front(r);
|
||||
if (queue_op_status::closed == st) break;
|
||||
if (queue_op_status::success == st) {
|
||||
mos << i << " pull(" << r << ")\n";
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
@@ -76,7 +87,7 @@ void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_q
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
//void consumer3(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
//void consumer3(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
//{
|
||||
// using namespace boost;
|
||||
// bool closed=false;
|
||||
@@ -100,11 +111,17 @@ int main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
#ifdef XXXX
|
||||
recursive_mutex terminal_mutex;
|
||||
|
||||
externally_locked_stream<std::ostream> mcerr(std::cerr, terminal_mutex);
|
||||
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
|
||||
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);
|
||||
#else
|
||||
the_ostream &mcerr = std::cout;
|
||||
the_ostream &mcout = std::cerr;
|
||||
//the_istream &mcin = std::cin;
|
||||
#endif
|
||||
|
||||
sync_queue<int> sbq;
|
||||
|
||||
|
||||
@@ -7,76 +7,86 @@
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
//#define XXXX
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#ifdef XXXX
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
typedef boost::externally_locked_stream<std::ostream> the_ostream;
|
||||
#else
|
||||
typedef std::ostream the_ostream;
|
||||
typedef std::istream the_istream;
|
||||
#endif
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
|
||||
void producer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
void producer(the_ostream &/*mos*/, boost::sync_bounded_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
//sbq.push(i);
|
||||
sbq << i;
|
||||
mos << "push(" << i << ") "<< sbq.size()<<"\n";
|
||||
sbq.push_back(i);
|
||||
//sbq << i;
|
||||
//mos << "push_back(" << i << ") "<< sbq.size()<<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
//mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
void consumer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
void consumer(the_ostream &/*mos*/, boost::sync_bounded_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
//sbq.pull(r);
|
||||
sbq >> r;
|
||||
mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
|
||||
sbq.pull_front(r);
|
||||
//sbq >> r;
|
||||
//mos << i << " pull_front(" << r << ") "<< sbq.size()<<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
//mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
void consumer2(the_ostream &/*mos*/, boost::sync_bounded_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
bool closed=false;
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
sbq.pull(r, closed);
|
||||
if (closed) break;
|
||||
mos << i << " pull(" << r << ")\n";
|
||||
queue_op_status st = sbq.try_pull_front(r);
|
||||
if (queue_op_status::closed == st) break;
|
||||
if (queue_op_status::success == st) {
|
||||
//mos << i << " pull(" << r << ")\n";
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
//void consumer3(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
//void consumer3(the_ostream &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
//{
|
||||
// using namespace boost;
|
||||
// bool closed=false;
|
||||
@@ -86,25 +96,30 @@ void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_b
|
||||
// int r;
|
||||
// queue_op_status res = sbq.wait_and_pull(r);
|
||||
// if (res==queue_op_status::closed) break;
|
||||
// mos << i << " wait_and_pull(" << r << ")\n";
|
||||
// //mos << i << " wait_and_pull(" << r << ")\n";
|
||||
// this_thread::sleep_for(chrono::milliseconds(250));
|
||||
// }
|
||||
// }
|
||||
// catch(...)
|
||||
// {
|
||||
// mos << "exception !!!\n";
|
||||
// //mos << "exception !!!\n";
|
||||
// }
|
||||
//}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
#ifdef XXXX
|
||||
recursive_mutex terminal_mutex;
|
||||
|
||||
externally_locked_stream<std::ostream> mcerr(std::cerr, terminal_mutex);
|
||||
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
|
||||
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);
|
||||
#else
|
||||
the_ostream &mcerr = std::cout;
|
||||
the_ostream &mcout = std::cerr;
|
||||
//the_istream &mcin = std::cin;
|
||||
#endif
|
||||
|
||||
sync_bounded_queue<int> sbq(10);
|
||||
|
||||
|
||||
68
example/thread_pool.cpp
Normal file
68
example/thread_pool.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (C) 2012-2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
|
||||
void p1()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " P1" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
void p2()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " P2" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
void submit_some(boost::basic_thread_pool& tp) {
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::basic_thread_pool tp;
|
||||
submit_some(tp);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
70
example/user_scheduler.cpp
Normal file
70
example/user_scheduler.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright (C) 2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/executors/loop_executor.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
|
||||
void p1()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " P1" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
void p2()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " P2" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
void submit_some(boost::loop_executor& tp) {
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::loop_executor tp;
|
||||
submit_some(tp);
|
||||
tp.run_queued_closures();
|
||||
submit_some(tp);
|
||||
tp.run_queued_closures();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
53
example/with_lock_guard.cpp
Normal file
53
example/with_lock_guard.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// (C) Copyright 2013 Ruslan Baratov
|
||||
// Copyright (C) 2014 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See www.boost.org/libs/thread for documentation.
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <iostream> // std::cout
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <boost/thread/with_lock_guard.hpp>
|
||||
|
||||
boost::mutex m; // protection for 'x' and 'std::cout'
|
||||
int x;
|
||||
|
||||
#if defined(BOOST_NO_CXX11_LAMBDAS) || (defined BOOST_MSVC && _MSC_VER < 1700)
|
||||
void print_x() {
|
||||
++x;
|
||||
std::cout << "x = " << x << std::endl;
|
||||
}
|
||||
|
||||
void job() {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
boost::with_lock_guard(m, print_x);
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
|
||||
}
|
||||
}
|
||||
#else
|
||||
void job() {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
boost::with_lock_guard(
|
||||
m,
|
||||
[]() {
|
||||
++x;
|
||||
std::cout << "x = " << x << std::endl;
|
||||
}
|
||||
);
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
#if defined(BOOST_NO_CXX11_LAMBDAS) || (defined BOOST_MSVC && _MSC_VER < 1700)
|
||||
std::cout << "(no lambdas)" << std::endl;
|
||||
#endif
|
||||
boost::scoped_thread<> thread_1((boost::thread(job)));
|
||||
boost::scoped_thread<> thread_2((boost::thread(job)));
|
||||
boost::scoped_thread<> thread_3((boost::thread(job)));
|
||||
return 0;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, William E. Kempf
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
// (C) Copyright 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -17,14 +18,10 @@
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
#include <boost/function.hpp>
|
||||
#else
|
||||
#include <functional>
|
||||
#endif
|
||||
#include <boost/thread/detail/nullary_function.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_void.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/utility/result_of.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
@@ -33,13 +30,8 @@ namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
typedef function<void()> void_completion_function;
|
||||
typedef function<size_t()> size_completion_function;
|
||||
#else
|
||||
typedef std::function<void()> void_completion_function;
|
||||
typedef std::function<size_t()> size_completion_function;
|
||||
#endif
|
||||
typedef detail::nullary_function<void()> void_completion_function;
|
||||
typedef detail::nullary_function<size_t()> size_completion_function;
|
||||
|
||||
struct default_barrier_reseter
|
||||
{
|
||||
@@ -48,6 +40,17 @@ namespace boost
|
||||
size_(size)
|
||||
{
|
||||
}
|
||||
BOOST_THREAD_MOVABLE(default_barrier_reseter)
|
||||
|
||||
default_barrier_reseter(default_barrier_reseter const& other) BOOST_NOEXCEPT :
|
||||
size_(other.size_)
|
||||
{
|
||||
}
|
||||
default_barrier_reseter(BOOST_THREAD_RV_REF(default_barrier_reseter) other) BOOST_NOEXCEPT :
|
||||
size_(BOOST_THREAD_RV(other).size_)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int operator()()
|
||||
{
|
||||
return size_;
|
||||
@@ -59,15 +62,25 @@ namespace boost
|
||||
unsigned int size_;
|
||||
void_completion_function fct_;
|
||||
template <typename F>
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
void_functor_barrier_reseter(unsigned int size, BOOST_THREAD_RV_REF(F) funct)
|
||||
: size_(size), fct_(boost::move(funct))
|
||||
{}
|
||||
#else
|
||||
void_functor_barrier_reseter(unsigned int size, F funct)
|
||||
template <typename F>
|
||||
void_functor_barrier_reseter(unsigned int size, F& funct)
|
||||
: size_(size), fct_(funct)
|
||||
{}
|
||||
#endif
|
||||
|
||||
BOOST_THREAD_MOVABLE(void_functor_barrier_reseter)
|
||||
|
||||
void_functor_barrier_reseter(void_functor_barrier_reseter const& other) BOOST_NOEXCEPT :
|
||||
size_(other.size_), fct_(other.fct_)
|
||||
{
|
||||
}
|
||||
void_functor_barrier_reseter(BOOST_THREAD_RV_REF(void_functor_barrier_reseter) other) BOOST_NOEXCEPT :
|
||||
size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int operator()()
|
||||
{
|
||||
fct_();
|
||||
@@ -82,6 +95,16 @@ namespace boost
|
||||
size_(size), fct_(funct)
|
||||
{
|
||||
}
|
||||
BOOST_THREAD_MOVABLE(void_fct_ptr_barrier_reseter)
|
||||
|
||||
void_fct_ptr_barrier_reseter(void_fct_ptr_barrier_reseter const& other) BOOST_NOEXCEPT :
|
||||
size_(other.size_), fct_(other.fct_)
|
||||
{
|
||||
}
|
||||
void_fct_ptr_barrier_reseter(BOOST_THREAD_RV_REF(void_fct_ptr_barrier_reseter) other) BOOST_NOEXCEPT :
|
||||
size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_)
|
||||
{
|
||||
}
|
||||
unsigned int operator()()
|
||||
{
|
||||
fct_();
|
||||
@@ -105,31 +128,37 @@ namespace boost
|
||||
BOOST_THREAD_NO_COPYABLE( barrier)
|
||||
|
||||
explicit barrier(unsigned int count) :
|
||||
m_count(check_counter(count)), m_generation(0), fct_(thread_detail::default_barrier_reseter(count))
|
||||
m_count(check_counter(count)), m_generation(0), fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
barrier(
|
||||
unsigned int count,
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
BOOST_THREAD_RV_REF(F) funct,
|
||||
#else
|
||||
F funct,
|
||||
#endif
|
||||
typename enable_if<
|
||||
typename is_void<typename result_of<F>::type>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
m_generation(0),
|
||||
fct_(thread_detail::void_functor_barrier_reseter(count,
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
boost::move(funct)
|
||||
#else
|
||||
funct
|
||||
#endif
|
||||
)
|
||||
m_generation(0),
|
||||
fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count,
|
||||
boost::move(funct)))
|
||||
)
|
||||
{
|
||||
}
|
||||
template <typename F>
|
||||
barrier(
|
||||
unsigned int count,
|
||||
F &funct,
|
||||
typename enable_if<
|
||||
typename is_void<typename result_of<F>::type>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
m_generation(0),
|
||||
fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count,
|
||||
funct))
|
||||
)
|
||||
{
|
||||
}
|
||||
@@ -137,40 +166,43 @@ namespace boost
|
||||
template <typename F>
|
||||
barrier(
|
||||
unsigned int count,
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
BOOST_THREAD_RV_REF(F) funct,
|
||||
#else
|
||||
F funct,
|
||||
#endif
|
||||
typename enable_if<
|
||||
typename is_same<typename result_of<F>::type, unsigned int>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
m_generation(0),
|
||||
fct_(
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
boost::move(funct)
|
||||
#else
|
||||
funct
|
||||
#endif
|
||||
m_generation(0),
|
||||
fct_(boost::move(funct))
|
||||
{
|
||||
}
|
||||
template <typename F>
|
||||
barrier(
|
||||
unsigned int count,
|
||||
F& funct,
|
||||
typename enable_if<
|
||||
typename is_same<typename result_of<F>::type, unsigned int>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
m_generation(0),
|
||||
fct_(funct)
|
||||
{
|
||||
}
|
||||
|
||||
barrier(unsigned int count, void(*funct)()) :
|
||||
m_count(check_counter(count)), m_generation(0),
|
||||
fct_(funct
|
||||
? thread_detail::size_completion_function(thread_detail::void_fct_ptr_barrier_reseter(count, funct))
|
||||
: thread_detail::size_completion_function(thread_detail::default_barrier_reseter(count))
|
||||
? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_fct_ptr_barrier_reseter(count, funct))))
|
||||
: BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count))))
|
||||
)
|
||||
{
|
||||
}
|
||||
barrier(unsigned int count, unsigned int(*funct)()) :
|
||||
m_count(check_counter(count)), m_generation(0),
|
||||
fct_(funct
|
||||
? thread_detail::size_completion_function(funct)
|
||||
: thread_detail::size_completion_function(thread_detail::default_barrier_reseter(count))
|
||||
? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(funct))
|
||||
: BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count))))
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
56
include/boost/thread/caller_context.hpp
Normal file
56
include/boost/thread/caller_context.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// (C) Copyright 2013 Vicente J. Botet Escriba
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_CALL_CONTEXT_HPP
|
||||
#define BOOST_THREAD_CALL_CONTEXT_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#if defined BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/thread.hpp>
|
||||
#endif
|
||||
#include <boost/current_function.hpp>
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
struct caller_context_t
|
||||
{
|
||||
const char * filename;
|
||||
unsigned lineno;
|
||||
const char * func;
|
||||
caller_context_t(const char * filename, unsigned lineno, const char * func) :
|
||||
filename(filename), lineno(lineno), func(func)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#define BOOST_CONTEXTOF boost::caller_context_t(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION)
|
||||
|
||||
template <typename OStream>
|
||||
OStream& operator<<(OStream& os, caller_context_t const& ctx)
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
{
|
||||
io::ios_flags_saver ifs( os );
|
||||
os << std::left << std::setw(14) << boost::this_thread::get_id() << " ";
|
||||
}
|
||||
#endif
|
||||
{
|
||||
io::ios_flags_saver ifs(os);
|
||||
os << ctx.filename << "["
|
||||
<< std::setw(4) << std::right << std::dec<< ctx.lineno << "] ";
|
||||
os << ctx.func << " " ;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -16,12 +16,8 @@
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
#include <boost/function.hpp>
|
||||
#else
|
||||
#include <functional>
|
||||
#endif
|
||||
//#include <boost/thread/latch.hpp>
|
||||
//#include <boost/thread/detail/nullary_function.hpp>
|
||||
#include <boost/thread/csbl/functional.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -37,11 +33,8 @@ namespace boost
|
||||
{
|
||||
public:
|
||||
/// the implementation defined completion function type
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
typedef function<void()> completion_function;
|
||||
#else
|
||||
typedef std::function<void()> completion_function;
|
||||
#endif
|
||||
//typedef detail::nullary_function<void()> completion_function;
|
||||
typedef csbl::function<void()> completion_function;
|
||||
/// noop completion function factory
|
||||
static completion_function noop()
|
||||
{
|
||||
|
||||
37
include/boost/thread/csbl/deque.hpp
Normal file
37
include/boost/thread/csbl/deque.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_DEQUE_HPP
|
||||
#define BOOST_CSBL_DEQUE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_THREAD_USES_BOOST_DEQUE
|
||||
#define BOOST_THREAD_USES_BOOST_DEQUE
|
||||
#endif
|
||||
#include <boost/container/deque.hpp>
|
||||
#else
|
||||
#include <deque>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_BOOST_DEQUE
|
||||
using ::boost::container::deque;
|
||||
|
||||
#else
|
||||
using ::std::deque;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
49
include/boost/thread/csbl/functional.hpp
Normal file
49
include/boost/thread/csbl/functional.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_FUNCTIONAL_HPP
|
||||
#define BOOST_CSBL_FUNCTIONAL_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_FUNCTIONAL || defined BOOST_NO_CXX11_HDR_FUNCTIONAL || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_THREAD_USES_BOOST_FUNCTIONAL
|
||||
#define BOOST_THREAD_USES_BOOST_FUNCTIONAL
|
||||
#endif
|
||||
#include <boost/function.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_BOOST_FUNCTIONAL
|
||||
using ::boost::function;
|
||||
#else
|
||||
// D.8.1, base (deprecated):
|
||||
// 20.9.3, reference_wrapper:
|
||||
// 20.9.4, arithmetic operations:
|
||||
// 20.9.5, comparisons:
|
||||
// 20.9.6, logical operations:
|
||||
// 20.9.7, bitwise operations:
|
||||
// 20.9.8, negators:
|
||||
// 20.9.9, bind:
|
||||
// D.9, binders (deprecated):
|
||||
// D.8.2.1, adaptors (deprecated):
|
||||
// D.8.2.2, adaptors (deprecated):
|
||||
// 20.9.10, member function adaptors:
|
||||
// 20.9.11 polymorphic function wrappers:
|
||||
using ::std::function;
|
||||
// 20.9.12, hash function primary template:
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
35
include/boost/thread/csbl/list.hpp
Normal file
35
include/boost/thread/csbl/list.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_LIST_HPP
|
||||
#define BOOST_CSBL_LIST_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_LIST || defined BOOST_NO_CXX11_HDR_LIST || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_THREAD_USES_BOOST_LIST
|
||||
#define BOOST_THREAD_USES_BOOST_LIST
|
||||
#endif
|
||||
#include <boost/container/list.hpp>
|
||||
#else
|
||||
#include <list>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_BOOST_LIST
|
||||
using ::boost::container::list;
|
||||
#else
|
||||
using ::std::list;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
61
include/boost/thread/csbl/memory.hpp
Normal file
61
include/boost/thread/csbl/memory.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_HPP
|
||||
#define BOOST_CSBL_MEMORY_HPP
|
||||
|
||||
// 20.7.2 Header <memory> synopsis
|
||||
|
||||
// 20.7.3, pointer traits
|
||||
#include <boost/thread/csbl/memory/pointer_traits.hpp>
|
||||
|
||||
// 20.7.4, pointer safety
|
||||
// 20.7.5, pointer alignment function
|
||||
|
||||
// 20.7.6, allocator argument tag
|
||||
#include <boost/thread/csbl/memory/allocator_arg.hpp>
|
||||
|
||||
// 20.7.8, allocator traits
|
||||
#include <boost/thread/csbl/memory/allocator_traits.hpp>
|
||||
|
||||
// 20.7.7, uses_allocator
|
||||
#include <boost/thread/csbl/memory/scoped_allocator.hpp>
|
||||
|
||||
// 20.7.9, the default allocator:
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::allocator;
|
||||
}
|
||||
}
|
||||
// 20.7.10, raw storage iterator:
|
||||
// 20.7.11, temporary buffers:
|
||||
// 20.7.12, specialized algorithms:
|
||||
|
||||
// 20.8.1 class template unique_ptr:
|
||||
// default_delete
|
||||
#include <boost/thread/csbl/memory/default_delete.hpp>
|
||||
#include <boost/thread/csbl/memory/unique_ptr.hpp>
|
||||
|
||||
// 20.8.2.1, class bad_weak_ptr:
|
||||
// 20.8.2.2, class template shared_ptr:
|
||||
// 20.8.2.2.6, shared_ptr creation
|
||||
// 20.8.2.2.7, shared_ptr comparisons:
|
||||
// 20.8.2.2.8, shared_ptr specialized algorithms:
|
||||
// 20.8.2.2.9, shared_ptr casts:
|
||||
// 20.8.2.2.10, shared_ptr get_deleter:
|
||||
// 20.8.2.2.11, shared_ptr I/O:
|
||||
// 20.8.2.3, class template weak_ptr:
|
||||
// 20.8.2.3.6, weak_ptr specialized algorithms:
|
||||
// 20.8.2.3.7, class template owner_less:
|
||||
// 20.8.2.4, class template enable_shared_from_this:
|
||||
// 20.8.2.5, shared_ptr atomic access:
|
||||
// 20.8.2.6 hash support
|
||||
|
||||
#endif // header
|
||||
41
include/boost/thread/csbl/memory/allocator_arg.hpp
Normal file
41
include/boost/thread/csbl/memory/allocator_arg.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_ALLOCATOR_ARG_HPP
|
||||
#define BOOST_CSBL_MEMORY_ALLOCATOR_ARG_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.7.6, allocator argument tag
|
||||
#if defined BOOST_NO_CXX11_ALLOCATOR
|
||||
#include <boost/container/scoped_allocator.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::container::allocator_arg_t;
|
||||
using ::boost::container::allocator_arg;
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::allocator_arg_t;
|
||||
using ::std::allocator_arg;
|
||||
}
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_ALLOCATOR
|
||||
namespace boost
|
||||
{
|
||||
using ::boost::csbl::allocator_arg_t;
|
||||
using ::boost::csbl::allocator_arg;
|
||||
}
|
||||
#endif // header
|
||||
35
include/boost/thread/csbl/memory/allocator_traits.hpp
Normal file
35
include/boost/thread/csbl/memory/allocator_traits.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_ALLOCATOR_TRAITS_HPP
|
||||
#define BOOST_CSBL_MEMORY_ALLOCATOR_TRAITS_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.7.8, allocator traits
|
||||
#if defined BOOST_NO_CXX11_ALLOCATOR
|
||||
#include <boost/container/allocator_traits.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::container::allocator_traits;
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::allocator_traits;
|
||||
}
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_POINTER_TRAITS
|
||||
|
||||
#endif // header
|
||||
16
include/boost/thread/csbl/memory/config.hpp
Normal file
16
include/boost/thread/csbl/memory/config.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_CONFIG_HPP
|
||||
#define BOOST_CSBL_MEMORY_CONFIG_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#endif // header
|
||||
125
include/boost/thread/csbl/memory/default_delete.hpp
Normal file
125
include/boost/thread/csbl/memory/default_delete.hpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_DEFAULT_DELETE_HPP
|
||||
#define BOOST_CSBL_MEMORY_DEFAULT_DELETE_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.8.1 class template unique_ptr:
|
||||
// default_delete
|
||||
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
#include <boost/thread/csbl/memory/pointer_traits.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_scalar.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class _Ptr1, class _Ptr2,
|
||||
bool = is_same<typename remove_cv<typename pointer_traits<_Ptr1>::element_type>::type,
|
||||
typename remove_cv<typename pointer_traits<_Ptr2>::element_type>::type
|
||||
>::value
|
||||
>
|
||||
struct same_or_less_cv_qualified_imp
|
||||
: is_convertible<_Ptr1, _Ptr2>
|
||||
{};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified_imp<_Ptr1, _Ptr2, false>
|
||||
: false_type
|
||||
{};
|
||||
|
||||
template <class _Ptr1, class _Ptr2, bool = is_scalar<_Ptr1>::value &&
|
||||
!is_pointer<_Ptr1>::value>
|
||||
struct same_or_less_cv_qualified
|
||||
: same_or_less_cv_qualified_imp<_Ptr1, _Ptr2>
|
||||
{};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified<_Ptr1, _Ptr2, true>
|
||||
: false_type
|
||||
{};
|
||||
|
||||
}
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT
|
||||
{}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U>&,
|
||||
typename enable_if<is_convertible<U*, T*> >::type* = 0) BOOST_NOEXCEPT
|
||||
{}
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (T* ptr) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete<T[]>
|
||||
{
|
||||
public:
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT
|
||||
{}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U[]>&,
|
||||
typename enable_if<detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) BOOST_NOEXCEPT
|
||||
{}
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (U* ptr,
|
||||
typename enable_if<detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete [] ptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::default_delete;
|
||||
}
|
||||
}
|
||||
#endif // defined BOOST_NO_CXX11_SMART_PTR
|
||||
|
||||
namespace boost
|
||||
{
|
||||
using ::boost::csbl::default_delete;
|
||||
}
|
||||
#endif // header
|
||||
35
include/boost/thread/csbl/memory/pointer_traits.hpp
Normal file
35
include/boost/thread/csbl/memory/pointer_traits.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_POINTER_TRAITS_HPP
|
||||
#define BOOST_CSBL_MEMORY_POINTER_TRAITS_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.7.3, pointer traits
|
||||
#if defined BOOST_NO_CXX11_ALLOCATOR
|
||||
#include <boost/intrusive/pointer_traits.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::intrusive::pointer_traits;
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::pointer_traits;
|
||||
}
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_ALLOCATOR
|
||||
|
||||
#endif // header
|
||||
35
include/boost/thread/csbl/memory/scoped_allocator.hpp
Normal file
35
include/boost/thread/csbl/memory/scoped_allocator.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_SCOPED_ALLOCATOR_HPP
|
||||
#define BOOST_CSBL_MEMORY_SCOPED_ALLOCATOR_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.7.7, uses_allocator
|
||||
#if defined BOOST_NO_CXX11_ALLOCATOR
|
||||
#include <boost/container/scoped_allocator.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::container::uses_allocator;
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::uses_allocator;
|
||||
}
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_POINTER_TRAITS
|
||||
|
||||
#endif // header
|
||||
106
include/boost/thread/csbl/memory/unique_ptr.hpp
Normal file
106
include/boost/thread/csbl/memory/unique_ptr.hpp
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP
|
||||
#define BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.8.1 class template unique_ptr:
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
#include <boost/thread/csbl/memory/default_delete.hpp>
|
||||
|
||||
#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
template <class T, class D = default_delete<T> > class unique_ptr :
|
||||
public ::boost::interprocess::unique_ptr<T,D>
|
||||
{
|
||||
typedef ::boost::interprocess::unique_ptr<T,D> base_type;
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(unique_ptr)
|
||||
protected:
|
||||
//typedef typename base_type::nat nat;
|
||||
//typedef typename base_type::nullptr_t nullptr_t;
|
||||
struct nat {int for_bool;};
|
||||
struct nat2 {int for_nullptr;};
|
||||
typedef int nat2::*nullptr_t;
|
||||
|
||||
public:
|
||||
typedef typename base_type::element_type element_type;
|
||||
typedef typename base_type::deleter_type deleter_type;
|
||||
typedef typename base_type::pointer pointer;
|
||||
|
||||
unique_ptr() : base_type()
|
||||
{}
|
||||
explicit unique_ptr(pointer p): base_type(p)
|
||||
{}
|
||||
unique_ptr(pointer p
|
||||
,typename interprocess::ipcdetail::if_<interprocess::ipcdetail::is_reference<D>
|
||||
,D
|
||||
,typename interprocess::ipcdetail::add_reference<const D>::type>::type d)
|
||||
: base_type(p, d)
|
||||
{}
|
||||
unique_ptr(BOOST_RV_REF(unique_ptr) u)
|
||||
: base_type(boost::move(static_cast<base_type&>(u)))
|
||||
{}
|
||||
template <class U, class E>
|
||||
unique_ptr(BOOST_RV_REF_BEG unique_ptr<U, E> BOOST_RV_REF_END u,
|
||||
typename interprocess::ipcdetail::enable_if_c<
|
||||
interprocess::ipcdetail::is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value &&
|
||||
interprocess::ipcdetail::is_convertible<E, D>::value &&
|
||||
(
|
||||
!interprocess::ipcdetail::is_reference<D>::value ||
|
||||
interprocess::ipcdetail::is_same<D, E>::value
|
||||
)
|
||||
,
|
||||
nat
|
||||
>::type = nat())
|
||||
: base_type(boost::move(static_cast< ::boost::interprocess::unique_ptr<U,E>&>(u)))
|
||||
{}
|
||||
unique_ptr& operator=(BOOST_RV_REF(unique_ptr) u)
|
||||
{
|
||||
this->base_type::operator=(boost::move(static_cast<base_type&>(u)));
|
||||
return *this;
|
||||
}
|
||||
template <class U, class E>
|
||||
unique_ptr& operator=(BOOST_RV_REF_BEG unique_ptr<U, E> BOOST_RV_REF_END u)
|
||||
{
|
||||
this->base_type::template operator=<U,E>(boost::move(static_cast< ::boost::interprocess::unique_ptr<U,E>&>(u)));
|
||||
return *this;
|
||||
}
|
||||
unique_ptr& operator=(nullptr_t t)
|
||||
{
|
||||
this->base_type::operator=(t);
|
||||
return *this;
|
||||
}
|
||||
void swap(unique_ptr& u)
|
||||
{
|
||||
this->base_type::swap(u);
|
||||
}
|
||||
};
|
||||
template <class T, class D>
|
||||
class unique_ptr<T[], D> :
|
||||
public ::boost::interprocess::unique_ptr<T[],D>
|
||||
{
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::unique_ptr;
|
||||
}
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_SMART_PTR
|
||||
#endif // header
|
||||
45
include/boost/thread/csbl/tuple.hpp
Normal file
45
include/boost/thread/csbl/tuple.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_TUPLE_HPP
|
||||
#define BOOST_CSBL_TUPLE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_TUPLE || defined BOOST_NO_CXX11_HDR_TUPLE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#ifndef BOOST_THREAD_USES_BOOST_TUPLE
|
||||
#define BOOST_THREAD_USES_BOOST_TUPLE
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include <tuple>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_BOOST_TUPLE
|
||||
using ::boost::tuple;
|
||||
using ::boost::get;
|
||||
#else
|
||||
// 20.4.2, class template tuple:
|
||||
using ::std::tuple;
|
||||
using ::std::get;
|
||||
// 20.4.2.4, tuple creation functions:
|
||||
// 20.4.2.5, tuple helper classes:
|
||||
// 20.4.2.6, element access:
|
||||
// 20.4.2.7, relational operators:
|
||||
// 20.4.2.8, allocator-related traits
|
||||
// 20.4.2.9, specialized algorithms:
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
35
include/boost/thread/csbl/vector.hpp
Normal file
35
include/boost/thread/csbl/vector.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_VECTOR_HPP
|
||||
#define BOOST_CSBL_VECTOR_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_VECTOR || defined BOOST_NO_CXX11_HDR_VECTOR || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_THREAD_USES_BOOST_VECTOR
|
||||
#define BOOST_THREAD_USES_BOOST_VECTOR
|
||||
#endif
|
||||
#include <boost/container/vector.hpp>
|
||||
#else
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_BOOST_VECTOR
|
||||
using ::boost::container::vector;
|
||||
#else
|
||||
using ::std::vector;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
@@ -9,7 +9,7 @@
|
||||
#ifndef BOOST_THREAD_CV_STATUS_HPP
|
||||
#define BOOST_THREAD_CV_STATUS_HPP
|
||||
|
||||
#include <boost/detail/scoped_enum_emulation.hpp>
|
||||
#include <boost/core/scoped_enum.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
//#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
// ATTRIBUTE_MAY_ALIAS
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) > 302 \
|
||||
&& !defined(__INTEL_COMPILER)
|
||||
#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
|
||||
|
||||
// GCC since 3.3 has may_alias attribute that helps to alleviate optimizer issues with
|
||||
// regard to violation of the strict aliasing rules.
|
||||
@@ -240,7 +239,8 @@
|
||||
! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_AUTO) && \
|
||||
! defined(BOOST_THREAD_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
|
||||
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
@@ -248,6 +248,22 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ! defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_WHEN_ALL_WHEN_ANY
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ! defined(BOOST_NO_SFINAE_EXPR) &&
|
||||
// ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) &&
|
||||
// ! defined(BOOST_NO_CXX11_AUTO) &&
|
||||
// ! defined(BOOST_NO_CXX11_DECLTYPE) &&
|
||||
// ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) &&
|
||||
|
||||
|
||||
// MAKE_READY_AT_THREAD_EXIT
|
||||
#if ! defined BOOST_THREAD_PROVIDES_MAKE_READY_AT_THREAD_EXIT \
|
||||
@@ -363,7 +379,9 @@
|
||||
// compatibility with the rest of Boost's auto-linking code:
|
||||
#if defined(BOOST_THREAD_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
|
||||
# undef BOOST_THREAD_USE_LIB
|
||||
# define BOOST_THREAD_USE_DLL
|
||||
# if !defined(BOOST_THREAD_USE_DLL)
|
||||
# define BOOST_THREAD_USE_DLL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* BOOST_THREAD_DELETE_COPY_ASSIGN deletes the copy assignment when the compiler supports it or
|
||||
* makes it private.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_NO_CXX11_DELETED_FUNCTIONS
|
||||
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
|
||||
CLASS(CLASS const&) = delete; \
|
||||
|
||||
93
include/boost/thread/detail/function_wrapper.hpp
Normal file
93
include/boost/thread/detail/function_wrapper.hpp
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
// Make use of Boost.Move
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP
|
||||
#define BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/thread/detail/memory.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
|
||||
#include <boost/thread/csbl/memory/unique_ptr.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class function_wrapper
|
||||
{
|
||||
struct impl_base
|
||||
{
|
||||
virtual void call()=0;
|
||||
virtual ~impl_base()
|
||||
{
|
||||
}
|
||||
};
|
||||
typedef boost::csbl::unique_ptr<impl_base> impl_base_type;
|
||||
impl_base_type impl;
|
||||
template <typename F>
|
||||
struct impl_type: impl_base
|
||||
{
|
||||
F f;
|
||||
impl_type(F const &f_)
|
||||
: f(f_)
|
||||
{}
|
||||
impl_type(BOOST_THREAD_RV_REF(F) f_)
|
||||
: f(boost::move(f_))
|
||||
{}
|
||||
|
||||
void call()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(function_wrapper)
|
||||
|
||||
//#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template<typename F>
|
||||
function_wrapper(F const& f):
|
||||
impl(new impl_type<F>(f))
|
||||
{}
|
||||
//#endif
|
||||
template<typename F>
|
||||
function_wrapper(BOOST_THREAD_RV_REF(F) f):
|
||||
impl(new impl_type<F>(boost::forward<F>(f)))
|
||||
{}
|
||||
function_wrapper(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT :
|
||||
impl(other.impl)
|
||||
{
|
||||
other.impl = 0;
|
||||
}
|
||||
function_wrapper()
|
||||
: impl(0)
|
||||
{
|
||||
}
|
||||
~function_wrapper()
|
||||
{
|
||||
}
|
||||
|
||||
function_wrapper& operator=(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=other.impl;
|
||||
other.impl=0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{ impl->call();}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // header
|
||||
@@ -28,7 +28,11 @@
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/is_member_function_pointer.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
#include <functional>
|
||||
@@ -40,11 +44,11 @@ namespace boost
|
||||
{
|
||||
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_SFINAE_EXPR) && \
|
||||
#if ! defined(BOOST_NO_SFINAE_EXPR) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_AUTO)
|
||||
! defined(BOOST_THREAD_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
|
||||
|
||||
#define BOOST_THREAD_PROVIDES_INVOKE
|
||||
|
||||
@@ -58,6 +62,13 @@ namespace boost
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
template <class R, class Fp, class A0, class ...Args>
|
||||
inline auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...))
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Fp, class A0, class ...Args>
|
||||
inline auto
|
||||
@@ -66,6 +77,13 @@ namespace boost
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
template <class R, class Fp, class A0, class ...Args>
|
||||
inline auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...))
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// bullets 3 and 4
|
||||
|
||||
@@ -85,14 +103,38 @@ namespace boost
|
||||
return (*boost::forward<A0>(a0)).*f;
|
||||
}
|
||||
|
||||
template <class R, class Fp, class A0>
|
||||
inline auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype(boost::forward<A0>(a0).*f)
|
||||
{
|
||||
return boost::forward<A0>(a0).*f;
|
||||
}
|
||||
|
||||
template <class R, class Fp, class A0>
|
||||
inline auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype((*boost::forward<A0>(a0)).*f)
|
||||
{
|
||||
return (*boost::forward<A0>(a0)).*f;
|
||||
}
|
||||
|
||||
|
||||
// bullet 5
|
||||
|
||||
template <class R, class Fp, class ...Args>
|
||||
inline auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<Args>(args)...))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
template <class Fp, class ...Args>
|
||||
inline auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<Args>(args)...))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
// bullets 1 and 2
|
||||
@@ -105,21 +147,45 @@ namespace boost
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)();
|
||||
}
|
||||
template <class R, class Fp, class A0>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype((boost::forward<A0>(a0).*f)())
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)();
|
||||
}
|
||||
template <class Fp, class A0, class A1>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<Args>(a1)))
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<Args>(a1));
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class R, class Fp, class A0, class A1>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Fp, class A0, class A1, class A2>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<Args>(a1), boost::forward<Args>(a2)))
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)))
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<Args>(a1), boost::forward<Args>(a2));
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class R, class Fp, class A0, class A1, class A2>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)))
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
|
||||
template <class Fp, class A0>
|
||||
@@ -130,21 +196,45 @@ namespace boost
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)();
|
||||
}
|
||||
template <class R, class Fp, class A0>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)())
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)();
|
||||
}
|
||||
template <class Fp, class A0, class A1>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(a1)))
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(a1));
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Fp, class A0, class A1>
|
||||
template <class R, class Fp, class A0, class A1>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Fp, class A0, class A1, class A2>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(a1), boost::forward<Args>(a2)))
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)))
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(a1), boost::forward<Args>(a2));
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class R, class Fp, class A0, class A1, class A2>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)))
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
|
||||
// bullets 3 and 4
|
||||
@@ -157,6 +247,14 @@ namespace boost
|
||||
{
|
||||
return boost::forward<A0>(a0).*f;
|
||||
}
|
||||
template <class R, class Fp, class A0>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype(boost::forward<A0>(a0).*f)
|
||||
{
|
||||
return boost::forward<A0>(a0).*f;
|
||||
}
|
||||
|
||||
template <class Fp, class A0>
|
||||
inline
|
||||
@@ -166,6 +264,14 @@ namespace boost
|
||||
{
|
||||
return (*boost::forward<A0>(a0)).*f;
|
||||
}
|
||||
template <class R, class Fp, class A0>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype((*boost::forward<A0>(a0)).*f)
|
||||
{
|
||||
return (*boost::forward<A0>(a0)).*f;
|
||||
}
|
||||
|
||||
// bullet 5
|
||||
|
||||
@@ -178,7 +284,7 @@ namespace boost
|
||||
}
|
||||
template <class Fp, class A1>
|
||||
inline
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) a1)
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1));
|
||||
@@ -197,12 +303,43 @@ namespace boost
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
|
||||
|
||||
template <class R, class Fp>
|
||||
inline
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f)
|
||||
-> decltype(boost::forward<Fp>(f)())
|
||||
{
|
||||
return boost::forward<Fp>(f)();
|
||||
}
|
||||
template <class R, class Fp, class A1>
|
||||
inline
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class R, class Fp, class A1, class A2>
|
||||
inline
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2)))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class R, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
|
||||
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
#elif ! defined(BOOST_NO_SFINAE_EXPR) && \
|
||||
! defined BOOST_NO_CXX11_HDR_FUNCTIONAL && \
|
||||
defined BOOST_MSVC
|
||||
|
||||
//#error
|
||||
template <class Ret, class Fp>
|
||||
inline
|
||||
Ret invoke(BOOST_THREAD_RV_REF(Fp) f)
|
||||
@@ -395,22 +532,28 @@ namespace boost
|
||||
// bullet 5
|
||||
// f(t1, t2, ..., tN) in all other cases.
|
||||
|
||||
template <class Ret, class Fp, class ...Args>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class ...Args>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
{
|
||||
return f(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class ...Args>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
template <class Ret, class ...Args>
|
||||
inline Ret
|
||||
invoke(Ret(*f)(Args... ), BOOST_THREAD_RV_REF(Args) ...args)
|
||||
{
|
||||
return f(boost::forward<Args>(args)...);
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<Args>(args)...);
|
||||
}
|
||||
#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
// bullet 1
|
||||
@@ -424,9 +567,34 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(), BOOST_THREAD_RV_REF(A0) a0)
|
||||
invoke(Ret (A::*f)(), A0& a0)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)();
|
||||
return (a0.*f)();
|
||||
}
|
||||
template <class Ret, class A, class A0>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(), A0* a0)
|
||||
{
|
||||
return ((*a0).*f)();
|
||||
}
|
||||
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1),
|
||||
A0& a0, BOOST_THREAD_RV_REF(A1) a1
|
||||
)
|
||||
{
|
||||
return (a0.*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
@@ -435,21 +603,33 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1), BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1), A0 a0, A1 a1)
|
||||
invoke(Ret (A::*f)(A1), A0& a0, A1 a1)
|
||||
{
|
||||
return (a0.*f)(a1);
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1), A0* a0, BOOST_THREAD_RV_REF(A1) a1
|
||||
)
|
||||
{
|
||||
return (*(a0).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1), A0* a0, A1 a1)
|
||||
{
|
||||
return (*a0.*f)(a1);
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1, class A2>
|
||||
inline
|
||||
typename enable_if_c
|
||||
@@ -458,10 +638,10 @@ namespace boost
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2),
|
||||
BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2
|
||||
A0& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2
|
||||
)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
return (a0.*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1, class A2>
|
||||
inline
|
||||
@@ -470,9 +650,9 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2), A0 a0, A1 a1, A2 a2)
|
||||
invoke(Ret (A::*f)(A1, A2), A0* a0, A1 a1, A2 a2)
|
||||
{
|
||||
return (a0.*f)(a1, a2);
|
||||
return ((*a0).*f)(a1, a2);
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1, class A2, class A3>
|
||||
inline
|
||||
@@ -482,9 +662,9 @@ namespace boost
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2, A3),
|
||||
BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
A0& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
return (a0.*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1, class A2, class A3>
|
||||
inline
|
||||
@@ -493,9 +673,9 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2, A3), A0 a0, A1 a1, A2 a2, A3 a3)
|
||||
invoke(Ret (A::*f)(A1, A2, A3), A0* a0, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return (a0.*f)(a1, a2, a3);
|
||||
return ((*a0).*f)(a1, a2, a3);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -506,9 +686,20 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)() const, BOOST_THREAD_RV_REF(A0) a0)
|
||||
invoke(Ret (A::*f)() const, A0 const& a0)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)();
|
||||
return (a0.*f)();
|
||||
}
|
||||
template <class Ret, class A, class A0>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)() const, A0 const* a0)
|
||||
{
|
||||
return ((*a0).*f)();
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
@@ -517,9 +708,9 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1) const, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
invoke(Ret (A::*f)(A1) const, A0 const& a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1));
|
||||
return (a0.*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
@@ -528,7 +719,19 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1) const, A0 a0, A1 a1)
|
||||
invoke(Ret (A::*f)(A1) const, A0 const* a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return ((*a0).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1) const, A0 const& a0, A1 a1)
|
||||
{
|
||||
return (a0.*f)(a1);
|
||||
}
|
||||
@@ -540,7 +743,7 @@ namespace boost
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2) const,
|
||||
BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2
|
||||
A0 const& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2
|
||||
)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)
|
||||
@@ -553,7 +756,7 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2) const, A0 a0, A1 a1, A2 a2)
|
||||
invoke(Ret (A::*f)(A1, A2) const, A0 const& a0, A1 a1, A2 a2)
|
||||
{
|
||||
return (a0.*f)(a1, a2);
|
||||
}
|
||||
@@ -1159,189 +1362,241 @@ namespace boost
|
||||
// f(t1, t2, ..., tN) in all other cases.
|
||||
|
||||
template <class Ret, class Fp>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f)
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f)
|
||||
{
|
||||
return boost::forward<Fp>(f)();
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
template <class Ret, class Fp>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f)
|
||||
{
|
||||
return f();
|
||||
}
|
||||
template <class Ret, class Fp>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f));
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, A1 a1)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, A1 a1, A2 a2)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1, a2);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1, a2, a3);
|
||||
}
|
||||
|
||||
///
|
||||
template <class Ret, class Fp>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f)
|
||||
{
|
||||
return f();
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return f(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, A1 a1)
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<A1>(a1));
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
|
||||
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1);
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1)
|
||||
{
|
||||
return f(a1);
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), a1);
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1, a2);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2)
|
||||
{
|
||||
return f(a1, a2);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), a1, a2);
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1, a2, a3);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return f(a1, a2, a3);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), a1, a2, a3);
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
template <class Ret, class Fp>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp &f)
|
||||
{
|
||||
return f();
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return f(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp &f, A1 a1)
|
||||
{
|
||||
return f(a1);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, A1 a1, A2 a2)
|
||||
invoke(Fp &f, A1 a1, A2 a2)
|
||||
{
|
||||
return f(a1, a2);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, A1 a1, A2 a2, A3 a3)
|
||||
invoke(Fp &f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return f(a1, a2, a3);
|
||||
}
|
||||
///
|
||||
|
||||
template <class Ret>
|
||||
inline Ret
|
||||
invoke(Ret(*f)())
|
||||
{
|
||||
return f();
|
||||
}
|
||||
template <class Ret, class A1>
|
||||
inline Ret
|
||||
invoke(Ret(*f)(A1), BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return f(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class A1, class A2>
|
||||
inline Ret
|
||||
invoke(Ret(*f)(A1, A2),
|
||||
BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class A1, class A2, class A3>
|
||||
inline Ret
|
||||
invoke(Ret(*f)(A1, A2, A3),
|
||||
BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
#endif // all
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
// The async_func code is based on the one from libcxx.
|
||||
// The invoker code is based on the one from libcxx.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
|
||||
@@ -29,39 +29,40 @@
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/detail/invoke.hpp>
|
||||
#include <boost/thread/detail/make_tuple_indices.hpp>
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
#include <tuple>
|
||||
#else
|
||||
#include <boost/thread/csbl/tuple.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/variadic_header.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
#if defined(BOOST_THREAD_PROVIDES_INVOKE) && ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
template <class Fp, class ... Args>
|
||||
class async_func
|
||||
class invoker
|
||||
{
|
||||
std::tuple<Fp, Args...> f_;
|
||||
//typedef typename decay<Fp>::type Fpd;
|
||||
//typedef tuple<typename decay<Args>::type...> Argsd;
|
||||
|
||||
//csbl::tuple<Fpd, Argsd...> f_;
|
||||
csbl::tuple<Fp, Args...> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY( async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY( invoker)
|
||||
//typedef typename invoke_of<_Fp, _Args...>::type Rp;
|
||||
typedef typename result_of<Fp(Args...)>::type result_type;
|
||||
|
||||
template <class F, class ... As>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args)... args)
|
||||
: f_(boost::move(f), boost::move(args)...)
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(As)... args)
|
||||
: f_(boost::forward<F>(f), boost::forward<As>(args)...)
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f) : f_(boost::move(f.f_))
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f) : f_(boost::move(BOOST_THREAD_RV(f).f_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -74,24 +75,165 @@ namespace boost
|
||||
result_type
|
||||
execute(tuple_indices<Indices...>)
|
||||
{
|
||||
return invoke(boost::move(std::get<0>(f_)), boost::move(std::get<Indices>(f_))...);
|
||||
return invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
|
||||
}
|
||||
};
|
||||
//BOOST_THREAD_DCL_MOVABLE_BEG(X) async_func<Fp> BOOST_THREAD_DCL_MOVABLE_END
|
||||
|
||||
template <class R, class Fp, class ... Args>
|
||||
class invoker_ret
|
||||
{
|
||||
//typedef typename decay<Fp>::type Fpd;
|
||||
//typedef tuple<typename decay<Args>::type...> Argsd;
|
||||
|
||||
//csbl::tuple<Fpd, Argsd...> f_;
|
||||
csbl::tuple<Fp, Args...> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY( invoker_ret)
|
||||
typedef R result_type;
|
||||
|
||||
template <class F, class ... As>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit invoker_ret(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(As)... args)
|
||||
: f_(boost::forward<F>(f), boost::forward<As>(args)...)
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker_ret(BOOST_THREAD_RV_REF(invoker_ret) f) : f_(boost::move(BOOST_THREAD_RV(f).f_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
typedef typename make_tuple_indices<1+sizeof...(Args), 1>::type Index;
|
||||
return execute(Index());
|
||||
}
|
||||
private:
|
||||
template <size_t ...Indices>
|
||||
result_type
|
||||
execute(tuple_indices<Indices...>)
|
||||
{
|
||||
return invoke<R>(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
|
||||
}
|
||||
};
|
||||
//BOOST_THREAD_DCL_MOVABLE_BEG(X) invoker<Fp> BOOST_THREAD_DCL_MOVABLE_END
|
||||
#else
|
||||
|
||||
#if ! defined BOOST_MSVC
|
||||
|
||||
#define BOOST_THREAD_RV_REF_ARG_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(Arg##n)
|
||||
#define BOOST_THREAD_RV_REF_A_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(A##n)
|
||||
#define BOOST_THREAD_RV_REF_ARG(z, n, unused) , BOOST_THREAD_RV_REF(Arg##n) arg##n
|
||||
#define BOOST_THREAD_FWD_REF_A(z, n, unused) , BOOST_THREAD_FWD_REF(A##n) arg##n
|
||||
#define BOOST_THREAD_FWD_REF_ARG(z, n, unused) , BOOST_THREAD_FWD_REF(Arg##n) arg##n
|
||||
#define BOOST_THREAD_FWD_PARAM(z, n, unused) , boost::forward<Arg##n>(arg##n)
|
||||
#define BOOST_THREAD_FWD_PARAM_A(z, n, unused) , boost::forward<A##n>(arg##n)
|
||||
#define BOOST_THREAD_DCL(z, n, unused) Arg##n v##n;
|
||||
#define BOOST_THREAD_MOVE_PARAM(z, n, unused) , v##n(boost::move(arg##n))
|
||||
#define BOOST_THREAD_FORWARD_PARAM_A(z, n, unused) , v##n(boost::forward<A##n>(arg##n))
|
||||
#define BOOST_THREAD_MOVE_RHS_PARAM(z, n, unused) , v##n(boost::move(x.v##n))
|
||||
#define BOOST_THREAD_MOVE_DCL(z, n, unused) , boost::move(v##n)
|
||||
#define BOOST_THREAD_MOVE_DCL_T(z, n, unused) BOOST_PP_COMMA_IF(n) boost::move(v##n)
|
||||
#define BOOST_THREAD_ARG_DEF(z, n, unused) , class Arg##n = tuples::null_type
|
||||
|
||||
template <class Fp, class Arg = tuples::null_type
|
||||
BOOST_PP_REPEAT(BOOST_THREAD_MAX_ARGS, BOOST_THREAD_ARG_DEF, ~)
|
||||
>
|
||||
class invoker;
|
||||
|
||||
#define BOOST_THREAD_ASYNC_FUNCT(z, n, unused) \
|
||||
template <class Fp BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class Arg) > \
|
||||
class invoker<Fp BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Arg)> \
|
||||
{ \
|
||||
Fp fp_; \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \
|
||||
public: \
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker) \
|
||||
typedef typename result_of<Fp(BOOST_PP_ENUM_PARAMS(n, Arg))>::type result_type; \
|
||||
\
|
||||
template <class F BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class A) > \
|
||||
BOOST_SYMBOL_VISIBLE \
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(F) f \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_FWD_REF_A, ~) \
|
||||
) \
|
||||
: fp_(boost::forward<F>(f)) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_FORWARD_PARAM_A, ~) \
|
||||
{} \
|
||||
\
|
||||
BOOST_SYMBOL_VISIBLE \
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) x) \
|
||||
: fp_(boost::move(x.fp_)) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \
|
||||
{} \
|
||||
\
|
||||
result_type operator()() { \
|
||||
return invoke(boost::move(fp_) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_DCL, ~) \
|
||||
); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <class R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class Arg) > \
|
||||
class invoker<R(*)(BOOST_PP_REPEAT(n, BOOST_THREAD_RV_REF_ARG_T, ~)) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Arg)> \
|
||||
{ \
|
||||
typedef R(*Fp)(BOOST_PP_REPEAT(n, BOOST_THREAD_RV_REF_ARG_T, ~)); \
|
||||
Fp fp_; \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \
|
||||
public: \
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker) \
|
||||
typedef typename result_of<Fp(BOOST_PP_ENUM_PARAMS(n, Arg))>::type result_type; \
|
||||
\
|
||||
template <class R2 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class A) > \
|
||||
BOOST_SYMBOL_VISIBLE \
|
||||
explicit invoker(R2(*f)(BOOST_PP_REPEAT(n, BOOST_THREAD_RV_REF_A_T, ~)) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_FWD_REF_A, ~) \
|
||||
) \
|
||||
: fp_(f) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_FORWARD_PARAM_A, ~) \
|
||||
{} \
|
||||
\
|
||||
BOOST_SYMBOL_VISIBLE \
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) x) \
|
||||
: fp_(x.fp_) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \
|
||||
{} \
|
||||
\
|
||||
result_type operator()() { \
|
||||
return fp_( \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_DCL_T, ~) \
|
||||
); \
|
||||
} \
|
||||
};
|
||||
|
||||
BOOST_PP_REPEAT(BOOST_THREAD_MAX_ARGS, BOOST_THREAD_ASYNC_FUNCT, ~)
|
||||
|
||||
#undef BOOST_THREAD_RV_REF_ARG_T
|
||||
#undef BOOST_THREAD_RV_REF_ARG
|
||||
#undef BOOST_THREAD_FWD_REF_ARG
|
||||
#undef BOOST_THREAD_FWD_REF_A
|
||||
#undef BOOST_THREAD_FWD_PARAM
|
||||
#undef BOOST_THREAD_FWD_PARAM_A
|
||||
#undef BOOST_THREAD_DCL
|
||||
#undef BOOST_THREAD_MOVE_PARAM
|
||||
#undef BOOST_THREAD_MOVE_RHS_PARAM
|
||||
#undef BOOST_THREAD_MOVE_DCL
|
||||
#undef BOOST_THREAD_ARG_DEF
|
||||
#undef BOOST_THREAD_ASYNC_FUNCT
|
||||
|
||||
#else
|
||||
|
||||
template <class Fp,
|
||||
class T0 = tuples::null_type, class T1 = tuples::null_type, class T2 = tuples::null_type,
|
||||
class T3 = tuples::null_type, class T4 = tuples::null_type, class T5 = tuples::null_type,
|
||||
class T6 = tuples::null_type, class T7 = tuples::null_type, class T8 = tuples::null_type
|
||||
, class T9 = tuples::null_type
|
||||
>
|
||||
class async_func;
|
||||
class invoker;
|
||||
|
||||
template <class Fp,
|
||||
class T0 , class T1 , class T2 ,
|
||||
class T3 , class T4 , class T5 ,
|
||||
class T6 , class T7 , class T8 >
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -106,11 +248,11 @@ namespace boost
|
||||
//::boost::tuple<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7, T8)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -134,17 +276,17 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
, v6_(boost::move(f.a6))
|
||||
, v7_(boost::move(f.a7))
|
||||
, v8_(boost::move(f.a8))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
, v4_(boost::move(BOOST_THREAD_RV(f).v4_))
|
||||
, v5_(boost::move(BOOST_THREAD_RV(f).v5_))
|
||||
, v6_(boost::move(BOOST_THREAD_RV(f).v6_))
|
||||
, v7_(boost::move(BOOST_THREAD_RV(f).v7_))
|
||||
, v8_(boost::move(BOOST_THREAD_RV(f).v8_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -163,7 +305,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7 >
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6, T7>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5, T6, T7>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -175,11 +317,11 @@ namespace boost
|
||||
T6 v6_;
|
||||
T7 v7_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -201,16 +343,16 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
, v6_(boost::move(f.a6))
|
||||
, v7_(boost::move(f.a7))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
, v4_(boost::move(BOOST_THREAD_RV(f).v4_))
|
||||
, v5_(boost::move(BOOST_THREAD_RV(f).v5_))
|
||||
, v6_(boost::move(BOOST_THREAD_RV(f).v6_))
|
||||
, v7_(boost::move(BOOST_THREAD_RV(f).v7_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -228,7 +370,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5, T6>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -239,11 +381,11 @@ namespace boost
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -263,15 +405,15 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
, v6_(boost::move(f.a6))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
, v4_(boost::move(BOOST_THREAD_RV(f).v4_))
|
||||
, v5_(boost::move(BOOST_THREAD_RV(f).v5_))
|
||||
, v6_(boost::move(BOOST_THREAD_RV(f).v6_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -288,7 +430,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5>
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -298,11 +440,11 @@ namespace boost
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -320,14 +462,14 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
, v4_(boost::move(BOOST_THREAD_RV(f).v4_))
|
||||
, v5_(boost::move(BOOST_THREAD_RV(f).v5_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -343,7 +485,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4>
|
||||
class async_func<Fp, T0, T1, T2, T3, T4>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -352,11 +494,11 @@ namespace boost
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -372,13 +514,13 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
, v4_(boost::move(BOOST_THREAD_RV(f).v4_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -393,7 +535,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3>
|
||||
class async_func<Fp, T0, T1, T2, T3>
|
||||
class invoker<Fp, T0, T1, T2, T3>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -401,11 +543,11 @@ namespace boost
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -419,12 +561,12 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -438,18 +580,18 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2>
|
||||
class async_func<Fp, T0, T1, T2>
|
||||
class invoker<Fp, T0, T1, T2>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -461,11 +603,11 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -478,17 +620,17 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1>
|
||||
class async_func<Fp, T0, T1>
|
||||
class invoker<Fp, T0, T1>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
)
|
||||
@@ -498,10 +640,10 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -513,16 +655,16 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0>
|
||||
class async_func<Fp, T0>
|
||||
class invoker<Fp, T0>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
@@ -530,9 +672,9 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -543,19 +685,19 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp>
|
||||
class async_func<Fp>
|
||||
class invoker<Fp>
|
||||
{
|
||||
Fp fp_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(async_func)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp()>::type result_type;
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_FWD_REF(Fp) f)
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f)
|
||||
: fp_(boost::move(f))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_FWD_REF(async_func) f)
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(f.fp_))
|
||||
{}
|
||||
result_type operator()()
|
||||
@@ -563,9 +705,34 @@ namespace boost
|
||||
return fp_();
|
||||
}
|
||||
};
|
||||
template <class R>
|
||||
class invoker<R(*)()>
|
||||
{
|
||||
typedef R(*Fp)();
|
||||
Fp fp_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp()>::type result_type;
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit invoker(Fp f)
|
||||
: fp_(f)
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(f.fp_)
|
||||
{}
|
||||
result_type operator()()
|
||||
{
|
||||
return fp_();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/thread/detail/variadic_footer.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -13,14 +13,11 @@
|
||||
#define BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/container/allocator_traits.hpp>
|
||||
#include <boost/container/scoped_allocator.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_scalar.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
#include <boost/thread/csbl/memory/pointer_traits.hpp>
|
||||
#include <boost/thread/csbl/memory/allocator_arg.hpp>
|
||||
#include <boost/thread/csbl/memory/allocator_traits.hpp>
|
||||
#include <boost/thread/csbl/memory/scoped_allocator.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -29,7 +26,7 @@ namespace boost
|
||||
template <class _Alloc>
|
||||
class allocator_destructor
|
||||
{
|
||||
typedef container::allocator_traits<_Alloc> alloc_traits;
|
||||
typedef csbl::allocator_traits<_Alloc> alloc_traits;
|
||||
public:
|
||||
typedef typename alloc_traits::pointer pointer;
|
||||
typedef typename alloc_traits::size_type size_type;
|
||||
@@ -47,111 +44,5 @@ namespace boost
|
||||
}
|
||||
};
|
||||
} //namespace thread_detail
|
||||
|
||||
typedef container::allocator_arg_t allocator_arg_t;
|
||||
BOOST_CONSTEXPR_OR_CONST allocator_arg_t allocator_arg = {};
|
||||
|
||||
template <class T, class Alloc>
|
||||
struct uses_allocator: public container::uses_allocator<T, Alloc>
|
||||
{
|
||||
};
|
||||
|
||||
template <class Ptr>
|
||||
struct pointer_traits
|
||||
{
|
||||
typedef Ptr pointer;
|
||||
// typedef <details> element_type;
|
||||
// typedef <details> difference_type;
|
||||
|
||||
// template <class U> using rebind = <details>;
|
||||
//
|
||||
// static pointer pointer_to(<details>);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct pointer_traits<T*>
|
||||
{
|
||||
typedef T* pointer;
|
||||
typedef T element_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
// template <class U> using rebind = U*;
|
||||
//
|
||||
// static pointer pointer_to(<details>) noexcept;
|
||||
};
|
||||
|
||||
|
||||
namespace thread_detail {
|
||||
template <class _Ptr1, class _Ptr2,
|
||||
bool = is_same<typename remove_cv<typename pointer_traits<_Ptr1>::element_type>::type,
|
||||
typename remove_cv<typename pointer_traits<_Ptr2>::element_type>::type
|
||||
>::value
|
||||
>
|
||||
struct same_or_less_cv_qualified_imp
|
||||
: is_convertible<_Ptr1, _Ptr2> {};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified_imp<_Ptr1, _Ptr2, false>
|
||||
: false_type {};
|
||||
|
||||
template <class _Ptr1, class _Ptr2, bool = is_scalar<_Ptr1>::value &&
|
||||
!is_pointer<_Ptr1>::value>
|
||||
struct same_or_less_cv_qualified
|
||||
: same_or_less_cv_qualified_imp<_Ptr1, _Ptr2> {};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified<_Ptr1, _Ptr2, true>
|
||||
: false_type {};
|
||||
|
||||
}
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT {}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U>&,
|
||||
typename enable_if<is_convertible<U*, T*> >::type* = 0) BOOST_NOEXCEPT {}
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (T* ptr) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete<T[]>
|
||||
{
|
||||
public:
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT {}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U[]>&,
|
||||
typename enable_if<thread_detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) BOOST_NOEXCEPT {}
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (U* ptr,
|
||||
typename enable_if<thread_detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete [] ptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
}
|
||||
#endif // BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
|
||||
@@ -9,18 +9,27 @@
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#include <boost/type_traits/conditional.hpp>
|
||||
#include <boost/type_traits/remove_extent.hpp>
|
||||
#include <boost/type_traits/is_array.hpp>
|
||||
#include <boost/type_traits/is_function.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/add_pointer.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/move/utility.hpp>
|
||||
#include <boost/move/traits.hpp>
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#include <type_traits>
|
||||
#endif
|
||||
namespace boost
|
||||
{
|
||||
|
||||
@@ -237,8 +246,51 @@ namespace detail
|
||||
|
||||
|
||||
namespace boost
|
||||
{ namespace thread_detail
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template <class Tp>
|
||||
struct remove_reference : boost::remove_reference<Tp> {};
|
||||
template <class Tp>
|
||||
struct decay : boost::decay<Tp> {};
|
||||
#else
|
||||
template <class Tp>
|
||||
struct remove_reference
|
||||
{
|
||||
typedef Tp type;
|
||||
};
|
||||
template <class Tp>
|
||||
struct remove_reference<Tp&>
|
||||
{
|
||||
typedef Tp type;
|
||||
};
|
||||
template <class Tp>
|
||||
struct remove_reference< rv<Tp> > {
|
||||
typedef Tp type;
|
||||
};
|
||||
|
||||
template <class Tp>
|
||||
struct decay
|
||||
{
|
||||
private:
|
||||
typedef typename boost::move_detail::remove_rvalue_reference<Tp>::type Up0;
|
||||
typedef typename boost::remove_reference<Up0>::type Up;
|
||||
public:
|
||||
typedef typename conditional
|
||||
<
|
||||
is_array<Up>::value,
|
||||
typename remove_extent<Up>::type*,
|
||||
typename conditional
|
||||
<
|
||||
is_function<Up>::value,
|
||||
typename add_pointer<Up>::type,
|
||||
typename remove_cv<Up>::type
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template <class T>
|
||||
typename decay<T>::type
|
||||
|
||||
213
include/boost/thread/detail/nullary_function.hpp
Normal file
213
include/boost/thread/detail/nullary_function.hpp
Normal file
@@ -0,0 +1,213 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
// Make use of Boost.Move
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_NULLARY_FUNCTION_HPP
|
||||
#define BOOST_THREAD_DETAIL_NULLARY_FUNCTION_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/thread/detail/memory.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename F>
|
||||
class nullary_function;
|
||||
template <>
|
||||
class nullary_function<void()>
|
||||
{
|
||||
struct impl_base
|
||||
{
|
||||
virtual void call()=0;
|
||||
virtual ~impl_base()
|
||||
{
|
||||
}
|
||||
};
|
||||
shared_ptr<impl_base> impl;
|
||||
template <typename F>
|
||||
struct impl_type: impl_base
|
||||
{
|
||||
F f;
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
impl_type(F &f_)
|
||||
: f(f_)
|
||||
{}
|
||||
#endif
|
||||
impl_type(BOOST_THREAD_RV_REF(F) f_)
|
||||
: f(boost::move(f_))
|
||||
{}
|
||||
|
||||
void call()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
struct impl_type_ptr: impl_base
|
||||
{
|
||||
void (*f)();
|
||||
impl_type_ptr(void (*f_)())
|
||||
: f(f_)
|
||||
{}
|
||||
void call()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE(nullary_function)
|
||||
|
||||
explicit nullary_function(void (*f)()):
|
||||
impl(new impl_type_ptr(f))
|
||||
{}
|
||||
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template<typename F>
|
||||
explicit nullary_function(F& f):
|
||||
impl(new impl_type<F>(f))
|
||||
{}
|
||||
#endif
|
||||
template<typename F>
|
||||
nullary_function(BOOST_THREAD_RV_REF(F) f):
|
||||
impl(new impl_type<typename decay<F>::type>(thread_detail::decay_copy(boost::forward<F>(f))))
|
||||
{}
|
||||
|
||||
nullary_function()
|
||||
: impl()
|
||||
{
|
||||
}
|
||||
nullary_function(nullary_function const& other) BOOST_NOEXCEPT :
|
||||
impl(other.impl)
|
||||
{
|
||||
}
|
||||
nullary_function(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT :
|
||||
impl(BOOST_THREAD_RV(other).impl)
|
||||
{
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
}
|
||||
~nullary_function()
|
||||
{
|
||||
}
|
||||
|
||||
nullary_function& operator=(nullary_function const& other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=other.impl;
|
||||
return *this;
|
||||
}
|
||||
nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=BOOST_THREAD_RV(other).impl;
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{ impl->call();}
|
||||
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
class nullary_function<R()>
|
||||
{
|
||||
struct impl_base
|
||||
{
|
||||
virtual R call()=0;
|
||||
virtual ~impl_base()
|
||||
{
|
||||
}
|
||||
};
|
||||
shared_ptr<impl_base> impl;
|
||||
template <typename F>
|
||||
struct impl_type: impl_base
|
||||
{
|
||||
F f;
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
impl_type(F &f_)
|
||||
: f(f_)
|
||||
{}
|
||||
#endif
|
||||
impl_type(BOOST_THREAD_RV_REF(F) f_)
|
||||
: f(boost::move(f_))
|
||||
{}
|
||||
|
||||
R call()
|
||||
{
|
||||
return f();
|
||||
}
|
||||
};
|
||||
struct impl_type_ptr: impl_base
|
||||
{
|
||||
R (*f)();
|
||||
impl_type_ptr(R (*f_)())
|
||||
: f(f_)
|
||||
{}
|
||||
|
||||
R call()
|
||||
{
|
||||
return f();
|
||||
}
|
||||
};
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE(nullary_function)
|
||||
|
||||
nullary_function(R (*f)()):
|
||||
impl(new impl_type_ptr(f))
|
||||
{}
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template<typename F>
|
||||
nullary_function(F& f):
|
||||
impl(new impl_type<F>(f))
|
||||
{}
|
||||
#endif
|
||||
template<typename F>
|
||||
nullary_function(BOOST_THREAD_RV_REF(F) f):
|
||||
impl(new impl_type<typename decay<F>::type>(thread_detail::decay_copy(boost::forward<F>(f))))
|
||||
{}
|
||||
|
||||
nullary_function(nullary_function const& other) BOOST_NOEXCEPT :
|
||||
impl(other.impl)
|
||||
{
|
||||
}
|
||||
nullary_function(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT :
|
||||
impl(BOOST_THREAD_RV(other).impl)
|
||||
{
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
}
|
||||
nullary_function()
|
||||
: impl()
|
||||
{
|
||||
}
|
||||
~nullary_function()
|
||||
{
|
||||
}
|
||||
|
||||
nullary_function& operator=(nullary_function const& other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=other.impl;
|
||||
return *this;
|
||||
}
|
||||
nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=BOOST_THREAD_RV(other).impl;
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
R operator()()
|
||||
{ return impl->call();}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // header
|
||||
@@ -4,7 +4,7 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-2010 Anthony Williams
|
||||
// (C) Copyright 20011-2012 Vicente J. Botet Escriba
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/core/ref.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/io/ios_state.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
@@ -64,11 +64,9 @@ namespace boost
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(thread_data)
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
thread_data(BOOST_THREAD_RV_REF(F) f_, BOOST_THREAD_RV_REF(ArgTypes)... args_):
|
||||
fp(boost::forward<F>(f_), boost::forward<ArgTypes>(args_)...)
|
||||
{}
|
||||
#endif
|
||||
template <std::size_t ...Indices>
|
||||
void run2(tuple_indices<Indices...>)
|
||||
{
|
||||
@@ -174,7 +172,7 @@ namespace boost
|
||||
private:
|
||||
bool start_thread_noexcept();
|
||||
bool start_thread_noexcept(const attributes& attr);
|
||||
public:
|
||||
//public:
|
||||
void start_thread()
|
||||
{
|
||||
if (!start_thread_noexcept())
|
||||
@@ -334,7 +332,7 @@ namespace boost
|
||||
start_thread(attrs);
|
||||
}
|
||||
#endif
|
||||
thread(BOOST_THREAD_RV_REF(thread) x)
|
||||
thread(BOOST_THREAD_RV_REF(thread) x) BOOST_NOEXCEPT
|
||||
{
|
||||
thread_info=BOOST_THREAD_RV(x).thread_info;
|
||||
BOOST_THREAD_RV(x).thread_info.reset();
|
||||
@@ -466,11 +464,20 @@ namespace boost
|
||||
inline void join();
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
template <class Rep, class Period>
|
||||
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
chrono::milliseconds rel_time2= chrono::ceil<chrono::milliseconds>(rel_time);
|
||||
return do_try_join_until(rel_time2.count());
|
||||
}
|
||||
#else
|
||||
template <class Rep, class Period>
|
||||
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_join_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
#endif
|
||||
template <class Clock, class Duration>
|
||||
bool try_join_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
@@ -546,6 +553,7 @@ namespace boost
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency() BOOST_NOEXCEPT;
|
||||
static unsigned physical_concurrency() BOOST_NOEXCEPT;
|
||||
|
||||
#define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE
|
||||
typedef detail::thread_data_base::native_handle_type native_handle_type;
|
||||
@@ -749,10 +757,10 @@ namespace boost
|
||||
#endif
|
||||
void thread::join() {
|
||||
if (this_thread::get_id() == get_id())
|
||||
boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
|
||||
boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
|
||||
|
||||
BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(),
|
||||
thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")
|
||||
thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -763,7 +771,7 @@ namespace boost
|
||||
#endif
|
||||
{
|
||||
if (this_thread::get_id() == get_id())
|
||||
boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
|
||||
boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
|
||||
bool res;
|
||||
if (do_try_join_until_noexcept(timeout, res))
|
||||
{
|
||||
@@ -772,7 +780,7 @@ namespace boost
|
||||
else
|
||||
{
|
||||
BOOST_THREAD_THROW_ELSE_RETURN(
|
||||
(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")),
|
||||
(thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace boost
|
||||
if(thrd)
|
||||
{
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( ! is_thread_in(thrd) ,
|
||||
thread_resource_error(system::errc::resource_deadlock_would_occur, "boost::thread_group: trying to add a duplicated thread")
|
||||
thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying to add a duplicated thread")
|
||||
);
|
||||
|
||||
boost::lock_guard<shared_mutex> guard(m);
|
||||
@@ -106,7 +106,7 @@ namespace boost
|
||||
void join_all()
|
||||
{
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( ! is_this_thread_in() ,
|
||||
thread_resource_error(system::errc::resource_deadlock_would_occur, "boost::thread_group: trying joining itself")
|
||||
thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying joining itself")
|
||||
);
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
|
||||
|
||||
10
include/boost/thread/detail/variadic_footer.hpp
Normal file
10
include/boost/thread/detail/variadic_footer.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#if defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
|
||||
#endif
|
||||
19
include/boost/thread/detail/variadic_header.hpp
Normal file
19
include/boost/thread/detail/variadic_header.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
//#if defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
#include <boost/preprocessor/facilities/intercept.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||
|
||||
#ifndef BOOST_THREAD_MAX_ARGS
|
||||
#define BOOST_THREAD_MAX_ARGS 9
|
||||
#endif
|
||||
|
||||
//#endif
|
||||
|
||||
23
include/boost/thread/detail/work.hpp
Normal file
23
include/boost/thread/detail/work.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
// (C) Copyright 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_WORK_HPP
|
||||
#define BOOST_THREAD_DETAIL_WORK_HPP
|
||||
|
||||
|
||||
#include <boost/thread/detail/nullary_function.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
|
||||
typedef detail::nullary_function<void()> work;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
44
include/boost/thread/exceptional_ptr.hpp
Normal file
44
include/boost/thread/exceptional_ptr.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2014 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_EXCEPTIONAL_PTR_HPP
|
||||
#define BOOST_THREAD_EXCEPTIONAL_PTR_HPP
|
||||
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/exception_ptr.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
struct exceptional_ptr {
|
||||
exception_ptr ptr_;
|
||||
|
||||
exceptional_ptr() : ptr_() {}
|
||||
explicit exceptional_ptr(exception_ptr ex) : ptr_(ex) {}
|
||||
template <class E>
|
||||
explicit exceptional_ptr(BOOST_FWD_REF(E) ex) : ptr_(boost::copy_exception(boost::forward<E>(ex))) {}
|
||||
};
|
||||
|
||||
template <class E>
|
||||
inline exceptional_ptr make_exceptional(BOOST_FWD_REF(E) ex) {
|
||||
return exceptional_ptr(boost::forward<E>(ex));
|
||||
}
|
||||
|
||||
inline exceptional_ptr make_exceptional(exception_ptr ex)
|
||||
{
|
||||
return exceptional_ptr(ex);
|
||||
}
|
||||
|
||||
inline exceptional_ptr make_exceptional()
|
||||
{
|
||||
return exceptional_ptr();
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -124,7 +124,7 @@ namespace boost
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
thread_resource_error()
|
||||
: base_type(system::errc::resource_unavailable_try_again, "boost::thread_resource_error")
|
||||
: base_type(static_cast<int>(system::errc::resource_unavailable_try_again), "boost::thread_resource_error")
|
||||
{}
|
||||
|
||||
thread_resource_error( int ev )
|
||||
@@ -152,7 +152,7 @@ namespace boost
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
unsupported_thread_option()
|
||||
: base_type(system::errc::invalid_argument, "boost::unsupported_thread_option")
|
||||
: base_type(static_cast<int>(system::errc::invalid_argument), "boost::unsupported_thread_option")
|
||||
{}
|
||||
|
||||
unsupported_thread_option( int ev )
|
||||
@@ -176,7 +176,7 @@ namespace boost
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
invalid_thread_argument()
|
||||
: base_type(system::errc::invalid_argument, "boost::invalid_thread_argument")
|
||||
: base_type(static_cast<int>(system::errc::invalid_argument), "boost::invalid_thread_argument")
|
||||
{}
|
||||
|
||||
invalid_thread_argument( int ev )
|
||||
@@ -200,7 +200,7 @@ namespace boost
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
thread_permission_error()
|
||||
: base_type(system::errc::permission_denied, "boost::thread_permission_error")
|
||||
: base_type(static_cast<int>(system::errc::permission_denied), "boost::thread_permission_error")
|
||||
{}
|
||||
|
||||
thread_permission_error( int ev )
|
||||
|
||||
15
include/boost/thread/executor.hpp
Normal file
15
include/boost/thread/executor.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/executors/executor_adaptor.hpp>
|
||||
|
||||
#endif
|
||||
326
include/boost/thread/executors/basic_thread_pool.hpp
Normal file
326
include/boost/thread/executors/basic_thread_pool.hpp
Normal file
@@ -0,0 +1,326 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
// first implementation of a simple pool thread using a vector of threads and a sync_queue.
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
class basic_thread_pool
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
private:
|
||||
/// the kind of stored threads are scoped threads to ensure that the threads are joined.
|
||||
/// A move aware vector type
|
||||
typedef scoped_thread<> thread_t;
|
||||
typedef csbl::vector<thread_t> thread_vector;
|
||||
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
/// A move aware vector
|
||||
thread_vector threads;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
work task;
|
||||
try
|
||||
{
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
{
|
||||
task();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Effects: schedule one task or yields
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
void schedule_one_or_yield()
|
||||
{
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
}
|
||||
private:
|
||||
|
||||
/**
|
||||
* The main loop of the worker threads
|
||||
*/
|
||||
void worker_thread()
|
||||
{
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <class AtThreadEntry>
|
||||
void worker_thread1(AtThreadEntry& at_thread_entry)
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void worker_thread2(void(*at_thread_entry)(basic_thread_pool&))
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
template <class AtThreadEntry>
|
||||
void worker_thread3(BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
static void do_nothing_at_thread_entry(basic_thread_pool&) {}
|
||||
|
||||
public:
|
||||
/// basic_thread_pool is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(basic_thread_pool)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a thread pool that runs closures on \c thread_count threads.
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency())
|
||||
{
|
||||
try
|
||||
{
|
||||
threads.reserve(thread_count);
|
||||
for (unsigned i = 0; i < thread_count; ++i)
|
||||
{
|
||||
#if 1
|
||||
thread th (&basic_thread_pool::worker_thread, this);
|
||||
threads.push_back(thread_t(boost::move(th)));
|
||||
#else
|
||||
threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* \b Effects: creates a thread pool that runs closures on \c thread_count threads
|
||||
* and executes the at_thread_entry function at the entry of each created thread. .
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <class AtThreadEntry>
|
||||
basic_thread_pool( unsigned const thread_count, AtThreadEntry& at_thread_entry)
|
||||
{
|
||||
try
|
||||
{
|
||||
threads.reserve(thread_count);
|
||||
for (unsigned i = 0; i < thread_count; ++i)
|
||||
{
|
||||
thread th (&basic_thread_pool::worker_thread1<AtThreadEntry>, this, at_thread_entry);
|
||||
threads.push_back(thread_t(boost::move(th)));
|
||||
//threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
basic_thread_pool( unsigned const thread_count, void(*at_thread_entry)(basic_thread_pool&))
|
||||
{
|
||||
try
|
||||
{
|
||||
threads.reserve(thread_count);
|
||||
for (unsigned i = 0; i < thread_count; ++i)
|
||||
{
|
||||
thread th (&basic_thread_pool::worker_thread2, this, at_thread_entry);
|
||||
threads.push_back(thread_t(boost::move(th)));
|
||||
//threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <class AtThreadEntry>
|
||||
basic_thread_pool( unsigned const thread_count, BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
|
||||
{
|
||||
try
|
||||
{
|
||||
threads.reserve(thread_count);
|
||||
for (unsigned i = 0; i < thread_count; ++i)
|
||||
{
|
||||
thread th (&basic_thread_pool::worker_thread3<AtThreadEntry>, this, boost::forward<AtThreadEntry>(at_thread_entry));
|
||||
threads.push_back(thread_t(boost::move(th)));
|
||||
//threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the thread pool.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c basic_thread_pool destructor.
|
||||
*/
|
||||
~basic_thread_pool()
|
||||
{
|
||||
// signal to all the worker threads that there will be no more submissions.
|
||||
close();
|
||||
// joins all the threads as the threads were scoped_threads
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c basic_thread_pool for submissions.
|
||||
* The worker threads will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
work_queue.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
return work_queue.closed();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the \c basic_thread_pool will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
//work w ((closure));
|
||||
//work_queue.push_back(boost::move(w));
|
||||
work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
//work w ((closure));
|
||||
//work_queue.push_back(boost::move(w));
|
||||
work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w = boost::move(closure);
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
|
||||
}
|
||||
#else
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
work_queue.push_back(work(boost::forward<Closure>(closure)));
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred)
|
||||
{
|
||||
do {
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (! pred());
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::basic_thread_pool;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
129
include/boost/thread/executors/executor.hpp
Normal file
129
include/boost/thread/executors/executor.hpp
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright (C) 2013,2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
class executor
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
|
||||
/// executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(executor)
|
||||
executor() {}
|
||||
|
||||
/**
|
||||
* \b Effects: Destroys the executor.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the executor destructor.
|
||||
*/
|
||||
virtual ~executor() {};
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c executor for submissions.
|
||||
* The worker threads will work until there is no more closures to run.
|
||||
*/
|
||||
virtual void close() = 0;
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
virtual bool closed() = 0;
|
||||
|
||||
/**
|
||||
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
virtual void submit(BOOST_THREAD_RV_REF(work) closure) = 0;
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the thread pool will call std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w = boost::move(closure);
|
||||
submit(boost::move(w));
|
||||
}
|
||||
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
virtual bool try_executing_one() = 0;
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred)
|
||||
{
|
||||
do {
|
||||
//schedule_one_or_yield();
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (! pred());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
using executors::executor;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
148
include/boost/thread/executors/executor_adaptor.hpp
Normal file
148
include/boost/thread/executors/executor_adaptor.hpp
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright (C) 2013,2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
/**
|
||||
* Polymorphic adaptor of a model of Executor to an executor.
|
||||
*/
|
||||
template <typename Executor>
|
||||
class executor_adaptor : public executor
|
||||
{
|
||||
Executor ex;
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executor::work work;
|
||||
|
||||
/// executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(executor_adaptor)
|
||||
|
||||
/**
|
||||
* executor_adaptor constructor
|
||||
*/
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <typename ...Args>
|
||||
executor_adaptor(BOOST_THREAD_RV_REF(Args) ... args) : ex(boost::forward<Args>(args)...) {}
|
||||
#else
|
||||
/**
|
||||
* executor_adaptor constructor
|
||||
*/
|
||||
executor_adaptor() : ex() {}
|
||||
|
||||
template <typename A1>
|
||||
executor_adaptor(
|
||||
BOOST_THREAD_FWD_REF(A1) a1
|
||||
) :
|
||||
ex(
|
||||
boost::forward<A1>(a1)
|
||||
) {}
|
||||
template <typename A1, typename A2>
|
||||
executor_adaptor(
|
||||
BOOST_THREAD_FWD_REF(A1) a1,
|
||||
BOOST_THREAD_FWD_REF(A2) a2
|
||||
) :
|
||||
ex(
|
||||
boost::forward<A1>(a1),
|
||||
boost::forward<A2>(a2)
|
||||
) {}
|
||||
template <typename A1, typename A2, typename A3>
|
||||
executor_adaptor(
|
||||
BOOST_THREAD_FWD_REF(A1) a1,
|
||||
BOOST_THREAD_FWD_REF(A2) a2,
|
||||
BOOST_THREAD_FWD_REF(A3) a3
|
||||
) :
|
||||
ex(
|
||||
boost::forward<A1>(a1),
|
||||
boost::forward<A2>(a2),
|
||||
boost::forward<A3>(a3)
|
||||
) {}
|
||||
#endif
|
||||
Executor& underlying_executor() { return ex; }
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c executor for submissions.
|
||||
* The worker threads will work until there is no more closures to run.
|
||||
*/
|
||||
void close() { ex.close(); }
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed() { return ex.closed(); }
|
||||
|
||||
/**
|
||||
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
void submit(BOOST_THREAD_RV_REF(work) closure) {
|
||||
return ex.submit(boost::move(closure));
|
||||
//return ex.submit(boost::forward<work>(closure));
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
//submit(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
//submit(work(closure));
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w =boost::move(closure);
|
||||
submit(boost::move(w));
|
||||
}
|
||||
#else
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
submit(work(boost::forward<Closure>(closure)));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one() { return ex.try_executing_one(); }
|
||||
|
||||
};
|
||||
}
|
||||
using executors::executor_adaptor;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
131
include/boost/thread/executors/inline_executor.hpp
Normal file
131
include/boost/thread/executors/inline_executor.hpp
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/11 Vicente J. Botet Escriba
|
||||
// first implementation of a simple serial scheduler.
|
||||
|
||||
#ifndef BOOST_THREAD_INLINE_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_INLINE_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
class inline_executor
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
bool closed_;
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
/// inline_executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(inline_executor)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a inline executor that runs closures immediately.
|
||||
*
|
||||
* \b Throws: Nothing.
|
||||
*/
|
||||
inline_executor()
|
||||
: closed_(false)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the inline executor.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c inline_executor destructor.
|
||||
*/
|
||||
~inline_executor()
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c inline_executor for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
closed_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the \c inline_executor will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
closure();
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
if (closed()) return;
|
||||
closure();
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
closure();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::inline_executor;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
209
include/boost/thread/executors/loop_executor.hpp
Normal file
209
include/boost/thread/executors/loop_executor.hpp
Normal file
@@ -0,0 +1,209 @@
|
||||
// Copyright (C) 2013,2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/11 Vicente J. Botet Escriba
|
||||
// first implementation of a simple user scheduler.
|
||||
// 2013/11 Vicente J. Botet Escriba
|
||||
// rename loop_executor.
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
class loop_executor
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
private:
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
work task;
|
||||
try
|
||||
{
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
{
|
||||
task();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* Effects: schedule one task or yields
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
void schedule_one_or_yield()
|
||||
{
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main loop of the worker thread
|
||||
*/
|
||||
void worker_thread()
|
||||
{
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/// loop_executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(loop_executor)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a thread pool that runs closures using one of its closure-executing methods.
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
loop_executor()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the thread pool.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c loop_executor destructor.
|
||||
*/
|
||||
~loop_executor()
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* loop
|
||||
*/
|
||||
void loop() { worker_thread(); }
|
||||
/**
|
||||
* \b Effects: close the \c loop_executor for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
work_queue.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
return work_queue.closed();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the \c loop_executor will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w =boost::move(closure);
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred)
|
||||
{
|
||||
do {
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (! pred());
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* run queued closures
|
||||
*/
|
||||
void run_queued_closures()
|
||||
{
|
||||
sync_queue<work>::underlying_queue_type q = work_queue.underlying_queue();
|
||||
while (q.empty())
|
||||
{
|
||||
work task = q.front();
|
||||
q.pop_front();
|
||||
task();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::loop_executor;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
213
include/boost/thread/executors/serial_executor.hpp
Normal file
213
include/boost/thread/executors/serial_executor.hpp
Normal file
@@ -0,0 +1,213 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/11 Vicente J. Botet Escriba
|
||||
// first implementation of a simple serial scheduler.
|
||||
|
||||
#ifndef BOOST_THREAD_SERIAL_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_SERIAL_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
class serial_executor
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
private:
|
||||
typedef scoped_thread<> thread_t;
|
||||
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
executor& ex;
|
||||
thread_t thr;
|
||||
|
||||
struct try_executing_one_task {
|
||||
work& task;
|
||||
boost::promise<void> &p;
|
||||
try_executing_one_task(work& task, boost::promise<void> &p)
|
||||
: task(task), p(p) {}
|
||||
void operator()() {
|
||||
task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here.
|
||||
p.set_value();
|
||||
}
|
||||
};
|
||||
public:
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
work task;
|
||||
try
|
||||
{
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
{
|
||||
boost::promise<void> p;
|
||||
try_executing_one_task tmp(task,p);
|
||||
ex.submit(tmp);
|
||||
// ex.submit([&task, &p]()
|
||||
// {
|
||||
// task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here.
|
||||
// p.set_value();
|
||||
// });
|
||||
p.get_future().wait();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* Effects: schedule one task or yields
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
void schedule_one_or_yield()
|
||||
{
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main loop of the worker thread
|
||||
*/
|
||||
void worker_thread()
|
||||
{
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/// serial_executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(serial_executor)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a thread pool that runs closures using one of its closure-executing methods.
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
serial_executor(executor& ex)
|
||||
: ex(ex), thr(&serial_executor::worker_thread, this)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the thread pool.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c serial_executor destructor.
|
||||
*/
|
||||
~serial_executor()
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c serial_executor for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
work_queue.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
return work_queue.closed();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the \c serial_executor will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w =boost::move(closure);
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred)
|
||||
{
|
||||
do {
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (! pred());
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::serial_executor;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
136
include/boost/thread/executors/thread_executor.hpp
Normal file
136
include/boost/thread/executors/thread_executor.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2014/01 Vicente J. Botet Escriba
|
||||
// first implementation of a thread_executor.
|
||||
|
||||
#ifndef BOOST_THREAD_THREAD_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_THREAD_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
class thread_executor
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
bool closed_;
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
/// thread_executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(thread_executor)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a inline executor that runs closures immediately.
|
||||
*
|
||||
* \b Throws: Nothing.
|
||||
*/
|
||||
thread_executor()
|
||||
: closed_(false)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the inline executor.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c thread_executor destructor.
|
||||
*/
|
||||
~thread_executor()
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c thread_executor for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
closed_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the \c thread_executor will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
thread th(closure);
|
||||
th.detach();
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
if (closed()) return;
|
||||
thread th(closure);
|
||||
th.detach();
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
thread th(boost::forward<Closure>(closure));
|
||||
th.detach();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::thread_executor;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
21
include/boost/thread/executors/work.hpp
Normal file
21
include/boost/thread/executors/work.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// (C) Copyright 2013,2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_WORK_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_WORK_HPP
|
||||
|
||||
|
||||
#include <boost/thread/detail/nullary_function.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
typedef detail::nullary_function<void()> work;
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_THREAD_EXECUTORS_WORK_HPP
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/utility/swap.hpp>
|
||||
#include <boost/core/swap.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace boost
|
||||
/// move assignment
|
||||
externally_locked& operator=(BOOST_THREAD_RV_REF(externally_locked) rhs) // BOOST_NOEXCEPT
|
||||
{
|
||||
obj_=move(rhs.obj_);
|
||||
obj_=move(BOOST_THREAD_RV(rhs).obj_);
|
||||
mtx_=rhs.mtx_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
||||
#define BOOST_THREAD_FUTURE_ERROR_CODE_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/detail/scoped_enum_emulation.hpp>
|
||||
#include <boost/core/scoped_enum.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
|
||||
@@ -29,11 +29,11 @@ namespace boost
|
||||
namespace system
|
||||
{
|
||||
template <>
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type {};
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum< ::boost::future_errc> : public true_type {};
|
||||
|
||||
#ifdef BOOST_NO_CXX11_SCOPED_ENUMS
|
||||
template <>
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type> : public true_type { };
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum< ::boost::future_errc::enum_type> : public true_type { };
|
||||
#endif
|
||||
} // system
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace boost
|
||||
error_condition
|
||||
make_error_condition(future_errc e) BOOST_NOEXCEPT
|
||||
{
|
||||
return error_condition(underlying_cast<int>(e), future_category());
|
||||
return error_condition(underlying_cast<int>(e), boost::future_category());
|
||||
}
|
||||
} // system
|
||||
} // boost
|
||||
|
||||
@@ -336,12 +336,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if (owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
m->lock();
|
||||
is_locked = true;
|
||||
@@ -351,12 +351,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if (owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked = m->try_lock();
|
||||
return is_locked;
|
||||
@@ -367,11 +367,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->timed_lock(relative_time);
|
||||
return is_locked;
|
||||
@@ -381,11 +381,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->timed_lock(absolute_time);
|
||||
return is_locked;
|
||||
@@ -394,11 +394,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->timed_lock(absolute_time);
|
||||
return is_locked;
|
||||
@@ -411,11 +411,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_for(rel_time);
|
||||
return is_locked;
|
||||
@@ -425,11 +425,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_until(abs_time);
|
||||
return is_locked;
|
||||
@@ -441,12 +441,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if (!owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock doesn't own the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock doesn't own the mutex"));
|
||||
}
|
||||
m->unlock();
|
||||
is_locked = false;
|
||||
@@ -636,11 +636,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
m->lock_shared();
|
||||
is_locked=true;
|
||||
@@ -649,11 +649,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_shared();
|
||||
return is_locked;
|
||||
@@ -663,11 +663,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->timed_lock_shared(target_time);
|
||||
return is_locked;
|
||||
@@ -677,11 +677,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->timed_lock_shared(target_time);
|
||||
return is_locked;
|
||||
@@ -693,11 +693,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_shared_for(rel_time);
|
||||
return is_locked;
|
||||
@@ -707,11 +707,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_shared_until(abs_time);
|
||||
return is_locked;
|
||||
@@ -721,11 +721,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(!owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock doesn't own the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock doesn't own the mutex"));
|
||||
}
|
||||
m->unlock_shared();
|
||||
is_locked=false;
|
||||
@@ -934,12 +934,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if (owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::resource_deadlock_would_occur, "boost upgrade_lock owns already the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex"));
|
||||
}
|
||||
m->lock_upgrade();
|
||||
is_locked = true;
|
||||
@@ -949,12 +949,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if (owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::resource_deadlock_would_occur, "boost upgrade_lock owns already the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex"));
|
||||
}
|
||||
is_locked = m->try_lock_upgrade();
|
||||
return is_locked;
|
||||
@@ -964,12 +964,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if (!owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost upgrade_lock doesn't own the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost upgrade_lock doesn't own the mutex"));
|
||||
}
|
||||
m->unlock_upgrade();
|
||||
is_locked = false;
|
||||
@@ -980,11 +980,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_upgrade_for(rel_time);
|
||||
return is_locked;
|
||||
@@ -994,11 +994,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_upgrade_until(abs_time);
|
||||
return is_locked;
|
||||
|
||||
@@ -37,11 +37,11 @@ namespace boost
|
||||
basic_lockable_adapter()
|
||||
{}
|
||||
|
||||
void lock()
|
||||
void lock() const
|
||||
{
|
||||
lockable().lock();
|
||||
}
|
||||
void unlock()
|
||||
void unlock() const
|
||||
{
|
||||
lockable().unlock();
|
||||
}
|
||||
@@ -56,7 +56,7 @@ namespace boost
|
||||
public:
|
||||
typedef Lockable mutex_type;
|
||||
|
||||
bool try_lock()
|
||||
bool try_lock() const
|
||||
{
|
||||
return this->lockable().try_lock();
|
||||
}
|
||||
@@ -71,12 +71,12 @@ namespace boost
|
||||
typedef TimedLock mutex_type;
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_lock_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_lock_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_lock_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_lock_for(rel_time);
|
||||
}
|
||||
@@ -91,26 +91,26 @@ namespace boost
|
||||
public:
|
||||
typedef SharableLock mutex_type;
|
||||
|
||||
void lock_shared()
|
||||
void lock_shared() const
|
||||
{
|
||||
this->lockable().lock_shared();
|
||||
}
|
||||
bool try_lock_shared()
|
||||
bool try_lock_shared() const
|
||||
{
|
||||
return this->lockable().try_lock_shared();
|
||||
}
|
||||
void unlock_shared()
|
||||
void unlock_shared() const
|
||||
{
|
||||
this->lockable().unlock_shared();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_shared_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_lock_shared_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_lock_shared_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_shared_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_lock_shared_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_lock_shared_for(rel_time);
|
||||
}
|
||||
@@ -126,95 +126,95 @@ namespace boost
|
||||
public:
|
||||
typedef UpgradableLock mutex_type;
|
||||
|
||||
void lock_upgrade()
|
||||
void lock_upgrade() const
|
||||
{
|
||||
this->lockable().lock_upgrade();
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
bool try_lock_upgrade() const
|
||||
{
|
||||
return this->lockable().try_lock_upgrade();
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
void unlock_upgrade() const
|
||||
{
|
||||
this->lockable().unlock_upgrade();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_lock_upgrade_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_lock_upgrade_for(rel_time);
|
||||
}
|
||||
|
||||
bool try_unlock_shared_and_lock()
|
||||
bool try_unlock_shared_and_lock() const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
void unlock_and_lock_shared() const
|
||||
{
|
||||
this->lockable().unlock_and_lock_shared();
|
||||
}
|
||||
|
||||
bool try_unlock_shared_and_lock_upgrade()
|
||||
bool try_unlock_shared_and_lock_upgrade() const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_upgrade();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_upgrade_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_upgrade_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
void unlock_and_lock_upgrade() const
|
||||
{
|
||||
this->lockable().unlock_and_lock_upgrade();
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
void unlock_upgrade_and_lock() const
|
||||
{
|
||||
this->lockable().unlock_upgrade_and_lock();
|
||||
}
|
||||
|
||||
bool try_unlock_upgrade_and_lock()
|
||||
bool try_unlock_upgrade_and_lock() const
|
||||
{
|
||||
return this->lockable().try_unlock_upgrade_and_lock();
|
||||
}
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_upgrade_and_lock_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_upgrade_and_lock_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
void unlock_upgrade_and_lock_shared() const
|
||||
{
|
||||
this->lockable().unlock_upgrade_and_lock_shared();
|
||||
}
|
||||
|
||||
45
include/boost/thread/ostream_buffer.hpp
Normal file
45
include/boost/thread/ostream_buffer.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// (C) Copyright 2013 Vicente J. Botet Escriba
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_OSTREAM_BUFFER_HPP
|
||||
#define BOOST_THREAD_OSTREAM_BUFFER_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template <typename OStream>
|
||||
class ostream_buffer
|
||||
{
|
||||
public:
|
||||
typedef std::basic_ostringstream<typename OStream::char_type, typename OStream::traits_type> stream_type;
|
||||
ostream_buffer(OStream& os) :
|
||||
os_(os)
|
||||
{
|
||||
}
|
||||
~ostream_buffer()
|
||||
{
|
||||
os_ << o_str_.str();
|
||||
}
|
||||
stream_type& stream()
|
||||
{
|
||||
return o_str_;
|
||||
}
|
||||
private:
|
||||
OStream& os_;
|
||||
stream_type o_str_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <pthread.h>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
@@ -105,7 +106,9 @@ namespace boost
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
|
||||
int const res = posix::pthread_mutex_destroy(&m);
|
||||
boost::ignore_unused(res);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
void lock()
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/detail/no_exceptions_support.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
@@ -42,7 +42,7 @@ namespace boost
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template<typename Function, class ...ArgTypes>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args);
|
||||
#else
|
||||
@@ -65,7 +65,7 @@ namespace boost
|
||||
private:
|
||||
volatile thread_detail::uintmax_atomic_t epoch;
|
||||
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template<typename Function, class ...ArgTypes>
|
||||
friend void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args);
|
||||
#else
|
||||
@@ -118,7 +118,7 @@ namespace boost
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
|
||||
|
||||
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
|
||||
|
||||
template<typename Function, class ...ArgTypes>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/detail/invoke.hpp>
|
||||
#include <boost/detail/no_exceptions_support.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/atomic.hpp>
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace boost
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
|
||||
template<typename Function, class ...ArgTypes>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
@@ -220,11 +219,11 @@ namespace boost
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
namespace hiden
|
||||
{
|
||||
void BOOST_THREAD_DECL sleep_for(const timespec& ts);
|
||||
void BOOST_THREAD_DECL sleep_until(const timespec& ts);
|
||||
}
|
||||
namespace hiden
|
||||
{
|
||||
void BOOST_THREAD_DECL sleep_for(const timespec& ts);
|
||||
void BOOST_THREAD_DECL sleep_until(const timespec& ts);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
|
||||
@@ -237,6 +236,27 @@ namespace boost
|
||||
#endif
|
||||
#endif // BOOST_THREAD_USES_CHRONO
|
||||
|
||||
namespace no_interruption_point
|
||||
{
|
||||
namespace hiden
|
||||
{
|
||||
void BOOST_THREAD_DECL sleep_for(const timespec& ts);
|
||||
void BOOST_THREAD_DECL sleep_until(const timespec& ts);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
|
||||
|
||||
inline
|
||||
void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
|
||||
{
|
||||
return boost::this_thread::hiden::sleep_for(boost::detail::to_timespec(ns));
|
||||
}
|
||||
#endif
|
||||
#endif // BOOST_THREAD_USES_CHRONO
|
||||
|
||||
} // no_interruption_point
|
||||
|
||||
void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
|
||||
@@ -47,13 +47,13 @@ namespace boost
|
||||
*
|
||||
*/
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type>
|
||||
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type>
|
||||
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
|
||||
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
|
||||
#else
|
||||
template <class F>
|
||||
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f,
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type=0) :
|
||||
t_(boost::forward<F>(f)) {}
|
||||
template <class F, class A1>
|
||||
strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) :
|
||||
@@ -137,13 +137,13 @@ namespace boost
|
||||
*/
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type>
|
||||
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type>
|
||||
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
|
||||
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
|
||||
#else
|
||||
template <class F>
|
||||
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f,
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type=0) :
|
||||
t_(boost::forward<F>(f)) {}
|
||||
template <class F, class A1>
|
||||
scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) :
|
||||
@@ -177,7 +177,7 @@ namespace boost
|
||||
* Move constructor.
|
||||
*/
|
||||
scoped_thread(BOOST_RV_REF(scoped_thread) x) BOOST_NOEXCEPT :
|
||||
t_(boost::move(x.t_))
|
||||
t_(boost::move(BOOST_THREAD_RV(x).t_))
|
||||
{}
|
||||
|
||||
/**
|
||||
@@ -197,7 +197,7 @@ namespace boost
|
||||
*/
|
||||
scoped_thread& operator=(BOOST_RV_REF(scoped_thread) x)
|
||||
{
|
||||
t_ = boost::move(x.t_);
|
||||
t_ = boost::move(BOOST_THREAD_RV(x).t_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -261,11 +261,17 @@ namespace boost
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned hardware_concurrency()BOOST_NOEXCEPT
|
||||
static unsigned hardware_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
return thread::hardware_concurrency();
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_PHYSICAL_CONCURRENCY
|
||||
static unsigned physical_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
return thread::physical_concurrency();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
@@ -28,10 +29,14 @@ namespace boost
|
||||
{ success = 0, empty, full, closed, busy }
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status)
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
struct no_block_tag{};
|
||||
BOOST_CONSTEXPR_OR_CONST no_block_tag no_block = {};
|
||||
#endif
|
||||
|
||||
struct sync_queue_is_closed : std::exception {};
|
||||
struct sync_queue_is_closed : std::exception
|
||||
{
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
class sync_bounded_queue
|
||||
@@ -57,22 +62,40 @@ namespace boost
|
||||
// Modifiers
|
||||
inline void close();
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(const value_type& x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, const value_type& x);
|
||||
inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
#endif
|
||||
inline void push_back(const value_type& x);
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push_back(const value_type& x);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push_back(const value_type& x);
|
||||
inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push_back(const value_type& x);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type&);
|
||||
inline void pull(ValueType& elem, bool & closed);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull();
|
||||
inline shared_ptr<ValueType> ptr_pull();
|
||||
inline bool try_pull(value_type&);
|
||||
inline bool try_pull(no_block_tag,value_type&);
|
||||
inline shared_ptr<ValueType> try_pull();
|
||||
#endif
|
||||
inline void pull_front(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull_front();
|
||||
inline queue_op_status try_pull_front(value_type&);
|
||||
inline queue_op_status nonblocking_pull_front(value_type&);
|
||||
|
||||
inline queue_op_status wait_pull_front(ValueType& elem);
|
||||
|
||||
private:
|
||||
mutable mutex mtx_;
|
||||
@@ -118,11 +141,21 @@ namespace boost
|
||||
}
|
||||
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline bool closed(unique_lock<mutex>&) const;
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
inline bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&);
|
||||
@@ -149,12 +182,20 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_]));
|
||||
@@ -162,6 +203,20 @@ namespace boost
|
||||
notify_not_full_if_needed(lk);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
inline void pull_front(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull_front(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
|
||||
inline void set_in(size_type in, unique_lock<mutex>& lk)
|
||||
{
|
||||
@@ -239,6 +294,11 @@ namespace boost
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed_;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::closed(unique_lock<mutex>& ) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::empty() const
|
||||
@@ -267,7 +327,7 @@ namespace boost
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
@@ -289,53 +349,61 @@ namespace boost
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
@@ -370,70 +438,74 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk, closed);
|
||||
if (closed) {return;}
|
||||
pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
// template <typename ValueType>
|
||||
// void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
// {
|
||||
// unique_lock<mutex> lk(mtx_);
|
||||
// wait_until_not_empty(lk, closed);
|
||||
// if (closed) {return;}
|
||||
// pull(elem, lk);
|
||||
// }
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
value_type elem;
|
||||
pull(elem);
|
||||
return boost::move(elem);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull_front()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull_front(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk) && closed(lk)) {return queue_op_status::closed;}
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
@@ -446,38 +518,67 @@ namespace boost
|
||||
push_at(elem, in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(elem, in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_push_back(elem, lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::wait_until_not_full(unique_lock<mutex>& lk)
|
||||
@@ -495,21 +596,22 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
@@ -526,70 +628,101 @@ namespace boost
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(boost::move(elem), in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push(boost::forward<ValueType>(elem));
|
||||
sbq.push_back(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push(elem);
|
||||
sbq.push_back(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull(elem);
|
||||
sbq.pull_front(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,20 +20,21 @@
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
#include <boost/container/deque.hpp>
|
||||
#include <boost/thread/csbl/deque.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
class sync_queue
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef csbl::deque<ValueType> underlying_queue_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef queue_op_status op_status;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_queue)
|
||||
@@ -51,28 +52,55 @@ namespace boost
|
||||
// Modifiers
|
||||
inline void close();
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(const value_type& x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
#endif
|
||||
inline void push_back(const value_type& x);
|
||||
inline queue_op_status try_push_back(const value_type& x);
|
||||
inline queue_op_status nonblocking_push_back(const value_type& x);
|
||||
inline queue_op_status wait_push_back(const value_type& x);
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
|
||||
// Observers/Modifiers
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type&);
|
||||
inline void pull(ValueType& elem, bool & closed);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull();
|
||||
inline shared_ptr<ValueType> ptr_pull();
|
||||
#endif
|
||||
inline void pull_front(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull_front();
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type&);
|
||||
inline bool try_pull(no_block_tag,value_type&);
|
||||
inline shared_ptr<ValueType> try_pull();
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type&);
|
||||
inline queue_op_status nonblocking_pull_front(value_type&);
|
||||
inline queue_op_status wait_pull_front(ValueType& elem);
|
||||
|
||||
inline underlying_queue_type underlying_queue() {
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return boost::move(data_);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
size_type waiting_empty_;
|
||||
boost::container::deque<ValueType> data_;
|
||||
underlying_queue_type data_;
|
||||
bool closed_;
|
||||
|
||||
inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
@@ -90,11 +118,20 @@ namespace boost
|
||||
}
|
||||
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline bool closed(unique_lock<mutex>& lk) const;
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&);
|
||||
@@ -109,18 +146,38 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type& elem, unique_lock<mutex>& )
|
||||
{
|
||||
elem = boost::move(data_.front());
|
||||
data_.pop_front();
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& )
|
||||
{
|
||||
value_type e = boost::move(data_.front());
|
||||
data_.pop_front();
|
||||
return boost::move(e);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& )
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_.front()));
|
||||
data_.pop_front();
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
inline void pull_front(value_type& elem, unique_lock<mutex>& )
|
||||
{
|
||||
elem = boost::move(data_.front());
|
||||
data_.pop_front();
|
||||
}
|
||||
inline value_type pull_front(unique_lock<mutex>& )
|
||||
{
|
||||
value_type e = boost::move(data_.front());
|
||||
data_.pop_front();
|
||||
return boost::move(e);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_.push_back(elem);
|
||||
@@ -129,7 +186,19 @@ namespace boost
|
||||
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_.push(boost::move(elem));
|
||||
data_.push_back(boost::move(elem));
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
#endif
|
||||
inline void push_back(const value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_.push_back(elem);
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_.push_back(boost::move(elem));
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
};
|
||||
@@ -184,6 +253,11 @@ namespace boost
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed_;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::closed(unique_lock<mutex>&) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::empty() const
|
||||
@@ -205,6 +279,7 @@ namespace boost
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
@@ -226,53 +301,81 @@ namespace boost
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
bool has_been_closed = false;
|
||||
wait_until_not_empty(lk, has_been_closed);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_queue<ValueType>::try_pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
@@ -308,70 +411,58 @@ namespace boost
|
||||
closed=false;
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk, closed);
|
||||
if (closed) {return;}
|
||||
pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_queue<ValueType>::pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
value_type elem;
|
||||
pull(elem);
|
||||
return boost::move(elem);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_queue<ValueType>::pull_front()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull_front(lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
@@ -383,126 +474,183 @@ namespace boost
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_back(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_back(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
throw_if_closed(lk);
|
||||
push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
push(boost::forward<ValueType>(elem), lk);
|
||||
push(boost::move(elem), lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_back(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_back(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
throw_if_closed(lk);
|
||||
push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push(boost::forward<ValueType>(elem));
|
||||
sbq.push_back(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push(elem);
|
||||
sbq.push_back(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull(elem);
|
||||
sbq.pull_front(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <boost/thread/lock_algorithms.hpp>
|
||||
#include <boost/thread/lock_factories.hpp>
|
||||
#include <boost/thread/strict_lock.hpp>
|
||||
#include <boost/utility/swap.hpp>
|
||||
#include <boost/core/swap.hpp>
|
||||
#include <boost/utility/declval.hpp>
|
||||
//#include <boost/type_traits.hpp>
|
||||
//#include <boost/thread/detail/is_nothrow_default_constructible.hpp>
|
||||
@@ -472,8 +472,8 @@ namespace boost
|
||||
*/
|
||||
synchronized_value(BOOST_THREAD_RV_REF(synchronized_value) other)
|
||||
{
|
||||
strict_lock<mutex_type> lk(other.mtx_);
|
||||
value_= boost::move(other.value_);
|
||||
strict_lock<mutex_type> lk(BOOST_THREAD_RV(other).mtx_);
|
||||
value_= boost::move(BOOST_THREAD_RV(other).value_);
|
||||
}
|
||||
|
||||
// mutation
|
||||
|
||||
15
include/boost/thread/thread_pool.hpp
Normal file
15
include/boost/thread/thread_pool.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
// first implementation of a simple pool thread using a vector of threads and a sync_queue.
|
||||
|
||||
#ifndef BOOST_THREAD_THREAD_POOL_HPP
|
||||
#define BOOST_THREAD_THREAD_POOL_HPP
|
||||
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
|
||||
#endif
|
||||
202
include/boost/thread/user_scheduler.hpp
Normal file
202
include/boost/thread/user_scheduler.hpp
Normal file
@@ -0,0 +1,202 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/11 Vicente J. Botet Escriba
|
||||
// first implementation of a simple serial scheduler.
|
||||
|
||||
#ifndef BOOST_THREAD_USER_SCHEDULER_HPP
|
||||
#define BOOST_THREAD_USER_SCHEDULER_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/detail/work.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
class user_scheduler
|
||||
{
|
||||
/// type-erasure to store the works to do
|
||||
typedef thread_detail::work work;
|
||||
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
work task;
|
||||
try
|
||||
{
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
{
|
||||
task();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* Effects: schedule one task or yields
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
void schedule_one_or_yield()
|
||||
{
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main loop of the worker thread
|
||||
*/
|
||||
void worker_thread()
|
||||
{
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/// user_scheduler is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(user_scheduler)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a thread pool that runs closures using one of its closure-executing methods.
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
user_scheduler()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the thread pool.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c user_scheduler destructor.
|
||||
*/
|
||||
~user_scheduler()
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* loop
|
||||
*/
|
||||
void loop() { worker_thread(); }
|
||||
/**
|
||||
* \b Effects: close the \c user_scheduler for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
work_queue.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
return work_queue.closed();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the \c user_scheduler will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w =boost::move(closure);
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred)
|
||||
{
|
||||
do {
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (! pred());
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* run queued closures
|
||||
*/
|
||||
void run_queued_closures()
|
||||
{
|
||||
sync_queue<work>::underlying_queue_type q = work_queue.underlying_queue();
|
||||
while (q.empty())
|
||||
{
|
||||
work task = q.front();
|
||||
q.pop_front();
|
||||
task();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -18,7 +18,66 @@ namespace boost
|
||||
{
|
||||
namespace this_thread
|
||||
{
|
||||
namespace no_interruption_point
|
||||
{
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
|
||||
template <class Clock, class Duration>
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
mutex mut;
|
||||
condition_variable cv;
|
||||
unique_lock<mutex> lk(mut);
|
||||
while (Clock::now() < t)
|
||||
cv.wait_until(lk, t);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
|
||||
|
||||
template <class Rep, class Period>
|
||||
void sleep_for(const chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
using namespace chrono;
|
||||
if (d > duration<Rep, Period>::zero())
|
||||
{
|
||||
duration<long double> Max = nanoseconds::max BOOST_PREVENT_MACRO_SUBSTITUTION ();
|
||||
nanoseconds ns;
|
||||
if (d < Max)
|
||||
{
|
||||
ns = duration_cast<nanoseconds>(d);
|
||||
if (ns < d)
|
||||
++ns;
|
||||
}
|
||||
else
|
||||
ns = nanoseconds:: max BOOST_PREVENT_MACRO_SUBSTITUTION ();
|
||||
sleep_for(ns);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
inline BOOST_SYMBOL_VISIBLE
|
||||
void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
sleep_for(t - steady_clock::now());
|
||||
}
|
||||
#else
|
||||
template <class Rep, class Period>
|
||||
void sleep_for(const chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
using namespace chrono;
|
||||
if (d > duration<Rep, Period>::zero())
|
||||
{
|
||||
steady_clock::time_point c_timeout = steady_clock::now() + ceil<nanoseconds>(d);
|
||||
sleep_until(c_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
|
||||
template <class Clock, class Duration>
|
||||
|
||||
@@ -337,7 +337,16 @@ namespace boost
|
||||
template<typename duration_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds());
|
||||
if (wait_duration.is_pos_infinity())
|
||||
{
|
||||
wait(m); // or do_wait(m,detail::timeout::sentinel());
|
||||
return true;
|
||||
}
|
||||
if (wait_duration.is_special())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return do_wait(m,wait_duration.total_milliseconds());
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/interlocked_read.hpp>
|
||||
#include <boost/detail/no_exceptions_support.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/detail/invoke.hpp>
|
||||
|
||||
@@ -227,7 +227,7 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
//#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
|
||||
inline void call_once(once_flag& flag, void (*f)())
|
||||
{
|
||||
|
||||
@@ -173,14 +173,14 @@ namespace boost
|
||||
static unsigned long const max_non_infinite_wait=0xfffffffe;
|
||||
|
||||
timeout(uintmax_t milliseconds_):
|
||||
start(win32::GetTickCount64()),
|
||||
start(win32::GetTickCount64()()),
|
||||
milliseconds(milliseconds_),
|
||||
relative(true),
|
||||
abs_time(boost::get_system_time())
|
||||
{}
|
||||
|
||||
timeout(boost::system_time const& abs_time_):
|
||||
start(win32::GetTickCount64()),
|
||||
start(win32::GetTickCount64()()),
|
||||
milliseconds(0),
|
||||
relative(false),
|
||||
abs_time(abs_time_)
|
||||
@@ -205,7 +205,7 @@ namespace boost
|
||||
}
|
||||
else if(relative)
|
||||
{
|
||||
win32::ticks_type const now=win32::GetTickCount64();
|
||||
win32::ticks_type const now=win32::GetTickCount64()();
|
||||
win32::ticks_type const elapsed=now-start;
|
||||
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
|
||||
}
|
||||
@@ -273,6 +273,33 @@ namespace boost
|
||||
interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count());
|
||||
}
|
||||
#endif
|
||||
namespace no_interruption_point
|
||||
{
|
||||
bool BOOST_THREAD_DECL non_interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
|
||||
inline void non_interruptible_wait(uintmax_t milliseconds)
|
||||
{
|
||||
non_interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
|
||||
}
|
||||
inline BOOST_SYMBOL_VISIBLE void non_interruptible_wait(system_time const& abs_time)
|
||||
{
|
||||
non_interruptible_wait(detail::win32::invalid_handle_value,abs_time);
|
||||
}
|
||||
template<typename TimeDuration>
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
non_interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds()));
|
||||
}
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time)
|
||||
{
|
||||
non_interruptible_wait(abs_time);
|
||||
}
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
|
||||
{
|
||||
non_interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <stdexcept>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/detail/no_exceptions_support.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
|
||||
@@ -18,12 +18,6 @@
|
||||
//#include <boost/detail/winapi/synchronization.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#ifndef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
#if _WIN32_WINNT >= 0x0600 && ! defined _WIN32_WINNT_WS08
|
||||
#define BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
|
||||
@@ -33,12 +27,6 @@ namespace boost
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
#ifdef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
typedef unsigned long long ticks_type;
|
||||
#else
|
||||
typedef unsigned long ticks_type;
|
||||
#endif
|
||||
typedef ULONG_PTR ulong_ptr;
|
||||
typedef HANDLE handle;
|
||||
unsigned const infinite=INFINITE;
|
||||
unsigned const timeout=WAIT_TIMEOUT;
|
||||
@@ -74,12 +62,6 @@ namespace boost
|
||||
using ::SleepEx;
|
||||
using ::Sleep;
|
||||
using ::QueueUserAPC;
|
||||
using ::GetTickCount;
|
||||
#ifdef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
using ::GetTickCount64;
|
||||
#else
|
||||
inline ticks_type GetTickCount64() { return GetTickCount(); }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,11 +96,6 @@ namespace boost
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
#ifdef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
typedef unsigned long long ticks_type;
|
||||
#else
|
||||
typedef unsigned long ticks_type;
|
||||
#endif
|
||||
# ifdef _WIN64
|
||||
typedef unsigned __int64 ulong_ptr;
|
||||
# else
|
||||
@@ -157,10 +134,6 @@ namespace boost
|
||||
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
|
||||
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
|
||||
|
||||
__declspec(dllimport) unsigned long __stdcall GetTickCount();
|
||||
# ifdef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
__declspec(dllimport) ticks_type __stdcall GetTickCount64();
|
||||
# endif
|
||||
# ifndef UNDER_CE
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
|
||||
@@ -177,9 +150,6 @@ namespace boost
|
||||
using ::ResetEvent;
|
||||
# endif
|
||||
}
|
||||
# ifndef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
inline ticks_type GetTickCount64() { return GetTickCount(); }
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,7 +165,88 @@ namespace boost
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
enum event_type
|
||||
typedef unsigned __int64 ticks_type;
|
||||
namespace detail { typedef int (__stdcall *farproc_t)(); typedef ticks_type (__stdcall *gettickcount64_t)(); }
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllimport) detail::farproc_t __stdcall GetProcAddress(void *, const char *);
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
__declspec(dllimport) void * __stdcall GetModuleHandleA(const char *);
|
||||
#else
|
||||
__declspec(dllimport) void * __stdcall GetModuleHandleW(const wchar_t *);
|
||||
#endif
|
||||
int __stdcall GetTickCount();
|
||||
long _InterlockedCompareExchange(long volatile *, long, long);
|
||||
#pragma intrinsic(_InterlockedCompareExchange)
|
||||
}
|
||||
// Borrowed from https://stackoverflow.com/questions/8211820/userland-interrupt-timer-access-such-as-via-kequeryinterrupttime-or-similar
|
||||
inline ticks_type __stdcall GetTickCount64emulation()
|
||||
{
|
||||
static volatile long count = 0xFFFFFFFF;
|
||||
unsigned long previous_count, current_tick32, previous_count_zone, current_tick32_zone;
|
||||
ticks_type current_tick64;
|
||||
|
||||
previous_count = (unsigned long) _InterlockedCompareExchange(&count, 0, 0);
|
||||
current_tick32 = GetTickCount();
|
||||
|
||||
if(previous_count == 0xFFFFFFFF)
|
||||
{
|
||||
// count has never been written
|
||||
unsigned long initial_count;
|
||||
initial_count = current_tick32 >> 28;
|
||||
previous_count = (unsigned long) _InterlockedCompareExchange(&count, initial_count, 0xFFFFFFFF);
|
||||
|
||||
current_tick64 = initial_count;
|
||||
current_tick64 <<= 28;
|
||||
current_tick64 += current_tick32 & 0x0FFFFFFF;
|
||||
return current_tick64;
|
||||
}
|
||||
|
||||
previous_count_zone = previous_count & 15;
|
||||
current_tick32_zone = current_tick32 >> 28;
|
||||
|
||||
if(current_tick32_zone == previous_count_zone)
|
||||
{
|
||||
// The top four bits of the 32-bit tick count haven't changed since count was last written.
|
||||
current_tick64 = previous_count;
|
||||
current_tick64 <<= 28;
|
||||
current_tick64 += current_tick32 & 0x0FFFFFFF;
|
||||
return current_tick64;
|
||||
}
|
||||
|
||||
if(current_tick32_zone == previous_count_zone + 1 || (current_tick32_zone == 0 && previous_count_zone == 15))
|
||||
{
|
||||
// The top four bits of the 32-bit tick count have been incremented since count was last written.
|
||||
_InterlockedCompareExchange(&count, previous_count + 1, previous_count);
|
||||
current_tick64 = previous_count + 1;
|
||||
current_tick64 <<= 28;
|
||||
current_tick64 += current_tick32 & 0x0FFFFFFF;
|
||||
return current_tick64;
|
||||
}
|
||||
|
||||
// Oops, we weren't called often enough, we're stuck
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
inline detail::gettickcount64_t GetTickCount64()
|
||||
{
|
||||
static detail::gettickcount64_t gettickcount64impl;
|
||||
if(gettickcount64impl)
|
||||
return gettickcount64impl;
|
||||
detail::farproc_t addr=GetProcAddress(
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
GetModuleHandleA("KERNEL32.DLL"),
|
||||
#else
|
||||
GetModuleHandleW(L"KERNEL32.DLL"),
|
||||
#endif
|
||||
"GetTickCount64");
|
||||
if(addr)
|
||||
gettickcount64impl=(detail::gettickcount64_t) addr;
|
||||
else
|
||||
gettickcount64impl=&GetTickCount64emulation;
|
||||
return gettickcount64impl;
|
||||
}
|
||||
|
||||
enum event_type
|
||||
{
|
||||
auto_reset_event=false,
|
||||
manual_reset_event=true
|
||||
|
||||
233
include/boost/thread/with_lock_guard.hpp
Normal file
233
include/boost/thread/with_lock_guard.hpp
Normal file
@@ -0,0 +1,233 @@
|
||||
// (C) Copyright 2013 Ruslan Baratov
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See www.boost.org/libs/thread for documentation.
|
||||
|
||||
#ifndef BOOST_THREAD_WITH_LOCK_GUARD_HPP
|
||||
#define BOOST_THREAD_WITH_LOCK_GUARD_HPP
|
||||
|
||||
#include <boost/thread/lock_guard.hpp>
|
||||
#include <boost/utility/result_of.hpp>
|
||||
//#include <boost/thread/detail/invoke.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
!defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
!defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
|
||||
|
||||
/**
|
||||
* Utility to run functions in scope protected by mutex.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* int func(int, int&);
|
||||
* boost::mutex m;
|
||||
* int a;
|
||||
* int result = boost::with_lock_guard(m, func, 1, boost::ref(a));
|
||||
*
|
||||
* // using boost::bind
|
||||
* int result = boost::with_lock_guard(
|
||||
* m, boost::bind(func, 2, boost::ref(a))
|
||||
* );
|
||||
*
|
||||
* // using lambda
|
||||
* int a;
|
||||
* int result = boost::with_lock_guard(
|
||||
* m,
|
||||
* [&a](int x) {
|
||||
* a = 3;
|
||||
* return x + 4;
|
||||
* },
|
||||
* 5
|
||||
* );
|
||||
*/
|
||||
template <class Lockable, class Function, class... Args>
|
||||
auto with_lock_guard(
|
||||
Lockable& m,
|
||||
BOOST_FWD_REF(Function) func,
|
||||
BOOST_FWD_REF(Args)... args
|
||||
) -> decltype(func(boost::forward<Args>(args)...)) {
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Workaround versions for compilers without c++11 variadic templates support.
|
||||
// (function arguments limit: 4)
|
||||
// (for lambda support define BOOST_RESULT_OF_USE_DECLTYPE may be needed)
|
||||
|
||||
template <class Lockable, class Func>
|
||||
typename boost::result_of<Func()>::type with_lock_guard(
|
||||
Lockable& m,
|
||||
BOOST_FWD_REF(Func) func
|
||||
) {
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func();
|
||||
}
|
||||
|
||||
template <class Lockable, class Func, class Arg>
|
||||
typename boost::result_of<Func(Arg)>::type with_lock_guard(
|
||||
Lockable& m,
|
||||
BOOST_FWD_REF(Func) func,
|
||||
BOOST_FWD_REF(Arg) arg
|
||||
) {
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(
|
||||
boost::forward<Arg>(arg)
|
||||
);
|
||||
}
|
||||
|
||||
template <class Lockable, class Func, class Arg1, class Arg2>
|
||||
typename boost::result_of<Func(Arg1, Arg2)>::type with_lock_guard(
|
||||
Lockable& m,
|
||||
BOOST_FWD_REF(Func) func,
|
||||
BOOST_FWD_REF(Arg1) arg1,
|
||||
BOOST_FWD_REF(Arg2) arg2
|
||||
) {
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(
|
||||
boost::forward<Arg1>(arg1),
|
||||
boost::forward<Arg2>(arg2)
|
||||
);
|
||||
}
|
||||
|
||||
template <class Lockable, class Func, class Arg1, class Arg2, class Arg3>
|
||||
typename boost::result_of<Func(Arg1, Arg2, Arg3)>::type with_lock_guard(
|
||||
Lockable& m,
|
||||
BOOST_FWD_REF(Func) func,
|
||||
BOOST_FWD_REF(Arg1) arg1,
|
||||
BOOST_FWD_REF(Arg2) arg2,
|
||||
BOOST_FWD_REF(Arg3) arg3
|
||||
) {
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(
|
||||
boost::forward<Arg1>(arg1),
|
||||
boost::forward<Arg2>(arg2),
|
||||
boost::forward<Arg3>(arg3)
|
||||
);
|
||||
}
|
||||
|
||||
template <
|
||||
class Lockable, class Func, class Arg1, class Arg2, class Arg3, class Arg4
|
||||
>
|
||||
typename boost::result_of<Func(Arg1, Arg2, Arg3, Arg4)>::type with_lock_guard(
|
||||
Lockable& m,
|
||||
BOOST_FWD_REF(Func) func,
|
||||
BOOST_FWD_REF(Arg1) arg1,
|
||||
BOOST_FWD_REF(Arg2) arg2,
|
||||
BOOST_FWD_REF(Arg3) arg3,
|
||||
BOOST_FWD_REF(Arg4) arg4
|
||||
) {
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(
|
||||
boost::forward<Arg1>(arg1),
|
||||
boost::forward<Arg2>(arg2),
|
||||
boost::forward<Arg3>(arg3),
|
||||
boost::forward<Arg4>(arg4)
|
||||
);
|
||||
}
|
||||
|
||||
// overloads for function pointer
|
||||
// (if argument is not function pointer, static assert will trigger)
|
||||
template <class Lockable, class Func>
|
||||
typename boost::result_of<
|
||||
typename boost::add_pointer<Func>::type()
|
||||
>::type with_lock_guard(
|
||||
Lockable& m,
|
||||
Func* func
|
||||
) {
|
||||
BOOST_STATIC_ASSERT(boost::is_function<Func>::value);
|
||||
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func();
|
||||
}
|
||||
|
||||
template <class Lockable, class Func, class Arg>
|
||||
typename boost::result_of<
|
||||
typename boost::add_pointer<Func>::type(Arg)
|
||||
>::type with_lock_guard(
|
||||
Lockable& m,
|
||||
Func* func,
|
||||
BOOST_FWD_REF(Arg) arg
|
||||
) {
|
||||
BOOST_STATIC_ASSERT(boost::is_function<Func>::value);
|
||||
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(
|
||||
boost::forward<Arg>(arg)
|
||||
);
|
||||
}
|
||||
|
||||
template <class Lockable, class Func, class Arg1, class Arg2>
|
||||
typename boost::result_of<
|
||||
typename boost::add_pointer<Func>::type(Arg1, Arg2)
|
||||
>::type with_lock_guard(
|
||||
Lockable& m,
|
||||
Func* func,
|
||||
BOOST_FWD_REF(Arg1) arg1,
|
||||
BOOST_FWD_REF(Arg2) arg2
|
||||
) {
|
||||
BOOST_STATIC_ASSERT(boost::is_function<Func>::value);
|
||||
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(
|
||||
boost::forward<Arg1>(arg1),
|
||||
boost::forward<Arg2>(arg2)
|
||||
);
|
||||
}
|
||||
|
||||
template <class Lockable, class Func, class Arg1, class Arg2, class Arg3>
|
||||
typename boost::result_of<
|
||||
typename boost::add_pointer<Func>::type(Arg1, Arg2, Arg3)
|
||||
>::type with_lock_guard(
|
||||
Lockable& m,
|
||||
Func* func,
|
||||
BOOST_FWD_REF(Arg1) arg1,
|
||||
BOOST_FWD_REF(Arg2) arg2,
|
||||
BOOST_FWD_REF(Arg3) arg3
|
||||
) {
|
||||
BOOST_STATIC_ASSERT(boost::is_function<Func>::value);
|
||||
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(
|
||||
boost::forward<Arg1>(arg1),
|
||||
boost::forward<Arg2>(arg2),
|
||||
boost::forward<Arg3>(arg3)
|
||||
);
|
||||
}
|
||||
|
||||
template <
|
||||
class Lockable, class Func, class Arg1, class Arg2, class Arg3, class Arg4
|
||||
>
|
||||
typename boost::result_of<
|
||||
typename boost::add_pointer<Func>::type(Arg1, Arg2, Arg3, Arg4)
|
||||
>::type with_lock_guard(
|
||||
Lockable& m,
|
||||
Func* func,
|
||||
BOOST_FWD_REF(Arg1) arg1,
|
||||
BOOST_FWD_REF(Arg2) arg2,
|
||||
BOOST_FWD_REF(Arg3) arg3,
|
||||
BOOST_FWD_REF(Arg4) arg4
|
||||
) {
|
||||
BOOST_STATIC_ASSERT(boost::is_function<Func>::value);
|
||||
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(
|
||||
boost::forward<Arg1>(arg1),
|
||||
boost::forward<Arg2>(arg2),
|
||||
boost::forward<Arg3>(arg3),
|
||||
boost::forward<Arg4>(arg4)
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_THREAD_WITH_LOCK_GUARD_HPP
|
||||
|
||||
20
meta/libraries.json
Normal file
20
meta/libraries.json
Normal file
@@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"key": "thread",
|
||||
"name": "Thread",
|
||||
"authors": [
|
||||
"Anthony Williams",
|
||||
"Vicente J. Botet Escriba"
|
||||
],
|
||||
"maintainers": [
|
||||
"Vicente J. Botet Escriba <vicente.botet -at- wanadoo.fr>",
|
||||
"Niall Douglas <niall -at- nedprod.com>"
|
||||
],
|
||||
"description":
|
||||
"Portable C++ multi-threading. C++11, C++14.",
|
||||
"std": [ "proposal" ],
|
||||
"category": [
|
||||
"Concurrent", "System"
|
||||
]
|
||||
}
|
||||
]
|
||||
1
src/future.cpp
Executable file → Normal file
1
src/future.cpp
Executable file → Normal file
@@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
#include <boost/thread/future_error_code.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
@@ -67,6 +68,7 @@ namespace boost
|
||||
if(!data)
|
||||
{
|
||||
data=malloc(sizeof(thread_detail::uintmax_atomic_t));
|
||||
if(!data) BOOST_THROW_EXCEPTION(std::bad_alloc());
|
||||
BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data));
|
||||
*static_cast<thread_detail::uintmax_atomic_t*>(data)=BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,15 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "./timeconv.inl"
|
||||
|
||||
namespace boost
|
||||
@@ -217,7 +226,7 @@ namespace boost
|
||||
|
||||
thread_data_base* make_external_thread_data()
|
||||
{
|
||||
thread_data_base* const me(new externally_launched_thread());
|
||||
thread_data_base* const me(detail::heap_new<externally_launched_thread>());
|
||||
me->self.reset(me);
|
||||
set_current_thread_data(me);
|
||||
return me;
|
||||
@@ -424,6 +433,68 @@ namespace boost
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
namespace no_interruption_point
|
||||
{
|
||||
namespace hiden
|
||||
{
|
||||
void BOOST_THREAD_DECL sleep_for(const timespec& ts)
|
||||
{
|
||||
|
||||
if (boost::detail::timespec_ge(ts, boost::detail::timespec_zero()))
|
||||
{
|
||||
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
# if defined(__IBMCPP__) || defined(_AIX)
|
||||
BOOST_VERIFY(!pthread_delay_np(const_cast<timespec*>(&ts)));
|
||||
# else
|
||||
BOOST_VERIFY(!pthread_delay_np(&ts));
|
||||
# endif
|
||||
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||
// nanosleep takes a timespec that is an offset, not
|
||||
// an absolute time.
|
||||
nanosleep(&ts, 0);
|
||||
# else
|
||||
mutex mx;
|
||||
unique_lock<mutex> lock(mx);
|
||||
condition_variable cond;
|
||||
cond.do_wait_for(lock, ts);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
void BOOST_THREAD_DECL sleep_until(const timespec& ts)
|
||||
{
|
||||
timespec now = boost::detail::timespec_now();
|
||||
if (boost::detail::timespec_gt(ts, now))
|
||||
{
|
||||
for (int foo=0; foo < 5; ++foo)
|
||||
{
|
||||
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
timespec d = boost::detail::timespec_minus(ts, now);
|
||||
BOOST_VERIFY(!pthread_delay_np(&d));
|
||||
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||
// nanosleep takes a timespec that is an offset, not
|
||||
// an absolute time.
|
||||
timespec d = boost::detail::timespec_minus(ts, now);
|
||||
nanosleep(&d, 0);
|
||||
# else
|
||||
mutex mx;
|
||||
unique_lock<mutex> lock(mx);
|
||||
condition_variable cond;
|
||||
cond.do_wait_until(lock, ts);
|
||||
# endif
|
||||
timespec now2 = boost::detail::timespec_now();
|
||||
if (boost::detail::timespec_ge(now2, ts))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
namespace hiden
|
||||
{
|
||||
void BOOST_THREAD_DECL sleep_for(const timespec& ts)
|
||||
@@ -437,27 +508,7 @@ namespace boost
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (boost::detail::timespec_ge(ts, boost::detail::timespec_zero()))
|
||||
{
|
||||
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
# if defined(__IBMCPP__)
|
||||
BOOST_VERIFY(!pthread_delay_np(const_cast<timespec*>(&ts)));
|
||||
# else
|
||||
BOOST_VERIFY(!pthread_delay_np(&ts));
|
||||
# endif
|
||||
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||
// nanosleep takes a timespec that is an offset, not
|
||||
// an absolute time.
|
||||
nanosleep(&ts, 0);
|
||||
# else
|
||||
mutex mx;
|
||||
unique_lock<mutex> lock(mx);
|
||||
condition_variable cond;
|
||||
cond.do_wait_for(lock, ts);
|
||||
# endif
|
||||
}
|
||||
boost::this_thread::no_interruption_point::hiden::sleep_for(ts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,37 +523,12 @@ namespace boost
|
||||
}
|
||||
else
|
||||
{
|
||||
timespec now = boost::detail::timespec_now();
|
||||
if (boost::detail::timespec_gt(ts, now))
|
||||
{
|
||||
for (int foo=0; foo < 5; ++foo)
|
||||
{
|
||||
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
timespec d = boost::detail::timespec_minus(ts, now);
|
||||
BOOST_VERIFY(!pthread_delay_np(&d));
|
||||
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||
// nanosleep takes a timespec that is an offset, not
|
||||
// an absolute time.
|
||||
timespec d = boost::detail::timespec_minus(ts, now);
|
||||
nanosleep(&d, 0);
|
||||
# else
|
||||
mutex mx;
|
||||
unique_lock<mutex> lock(mx);
|
||||
condition_variable cond;
|
||||
cond.do_wait_until(lock, ts);
|
||||
# endif
|
||||
timespec now2 = boost::detail::timespec_now();
|
||||
if (boost::detail::timespec_ge(now2, ts))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
boost::this_thread::no_interruption_point::hiden::sleep_until(ts);
|
||||
}
|
||||
}
|
||||
} // hiden
|
||||
} // this_thread
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
void yield() BOOST_NOEXCEPT
|
||||
@@ -543,6 +569,64 @@ namespace boost
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned thread::physical_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
#ifdef __linux__
|
||||
try {
|
||||
using namespace std;
|
||||
|
||||
ifstream proc_cpuinfo ("/proc/cpuinfo");
|
||||
|
||||
const string physical_id("physical id"), core_id("core id");
|
||||
|
||||
typedef std::pair<unsigned, unsigned> core_entry; // [physical ID, core id]
|
||||
|
||||
std::set<core_entry> cores;
|
||||
|
||||
core_entry current_core_entry;
|
||||
|
||||
string line;
|
||||
while ( getline(proc_cpuinfo, line) ) {
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
vector<string> key_val(2);
|
||||
boost::split(key_val, line, boost::is_any_of(":"));
|
||||
|
||||
if (key_val.size() != 2)
|
||||
return hardware_concurrency();
|
||||
|
||||
string key = key_val[0];
|
||||
string value = key_val[1];
|
||||
boost::trim(key);
|
||||
boost::trim(value);
|
||||
|
||||
if (key == physical_id) {
|
||||
current_core_entry.first = boost::lexical_cast<unsigned>(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key == core_id) {
|
||||
current_core_entry.second = boost::lexical_cast<unsigned>(value);
|
||||
cores.insert(current_core_entry);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Fall back to hardware_concurrency() in case
|
||||
// /proc/cpuinfo is formatted differently than we expect.
|
||||
return cores.size() != 0 ? cores.size() : hardware_concurrency();
|
||||
} catch(...) {
|
||||
return hardware_concurrency();
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
int count;
|
||||
size_t size=sizeof(count);
|
||||
return sysctlbyname("hw.physicalcpu",&count,&size,NULL,0)?0:count;
|
||||
#else
|
||||
return hardware_concurrency();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
void thread::interrupt()
|
||||
{
|
||||
@@ -670,7 +754,7 @@ namespace boost
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
thread_exit_callback_node* const new_node=
|
||||
new thread_exit_callback_node(func,current_thread_data->thread_exit_callbacks);
|
||||
heap_new<thread_exit_callback_node>(func,current_thread_data->thread_exit_callbacks);
|
||||
current_thread_data->thread_exit_callbacks=new_node;
|
||||
}
|
||||
|
||||
|
||||
@@ -407,6 +407,8 @@ namespace boost
|
||||
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
//SYSTEM_INFO info={{0}};
|
||||
@@ -414,7 +416,30 @@ namespace boost
|
||||
GetSystemInfo(&info);
|
||||
return info.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
unsigned thread::physical_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned cores = 0;
|
||||
#if !(defined(__MINGW32__) || defined (__MINGW64__))
|
||||
DWORD size = 0;
|
||||
|
||||
GetLogicalProcessorInformation(NULL, &size);
|
||||
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||
return 0;
|
||||
|
||||
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(size);
|
||||
if (GetLogicalProcessorInformation(&buffer.front(), &size) == FALSE)
|
||||
return 0;
|
||||
|
||||
const size_t Elements = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
|
||||
|
||||
for (size_t i = 0; i < Elements; ++i) {
|
||||
if (buffer[i].Relationship == RelationProcessorCore)
|
||||
++cores;
|
||||
}
|
||||
#endif
|
||||
return cores;
|
||||
}
|
||||
|
||||
thread::native_handle_type thread::native_handle()
|
||||
{
|
||||
@@ -436,7 +461,7 @@ namespace boost
|
||||
LARGE_INTEGER due_time={{0,0}};
|
||||
if(target_time.relative)
|
||||
{
|
||||
unsigned long const elapsed_milliseconds=detail::win32::GetTickCount64()-target_time.start;
|
||||
detail::win32::ticks_type const elapsed_milliseconds=detail::win32::GetTickCount64()()-target_time.start;
|
||||
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
|
||||
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
|
||||
|
||||
@@ -584,6 +609,90 @@ namespace boost
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace no_interruption_point
|
||||
{
|
||||
bool non_interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
|
||||
{
|
||||
detail::win32::handle handles[3]={0};
|
||||
unsigned handle_count=0;
|
||||
unsigned wait_handle_index=~0U;
|
||||
unsigned timeout_index=~0U;
|
||||
if(handle_to_wait_for!=detail::win32::invalid_handle_value)
|
||||
{
|
||||
wait_handle_index=handle_count;
|
||||
handles[handle_count++]=handle_to_wait_for;
|
||||
}
|
||||
detail::win32::handle_manager timer_handle;
|
||||
|
||||
#ifndef UNDER_CE
|
||||
unsigned const min_timer_wait_period=20;
|
||||
|
||||
if(!target_time.is_sentinel())
|
||||
{
|
||||
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
|
||||
if(time_left.milliseconds > min_timer_wait_period)
|
||||
{
|
||||
// for a long-enough timeout, use a waitable timer (which tracks clock changes)
|
||||
timer_handle=CreateWaitableTimer(NULL,false,NULL);
|
||||
if(timer_handle!=0)
|
||||
{
|
||||
LARGE_INTEGER due_time=get_due_time(target_time);
|
||||
|
||||
bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
|
||||
if(set_time_succeeded)
|
||||
{
|
||||
timeout_index=handle_count;
|
||||
handles[handle_count++]=timer_handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!target_time.relative)
|
||||
{
|
||||
// convert short absolute-time timeouts into relative ones, so we don't race against clock changes
|
||||
target_time=detail::timeout(time_left.milliseconds);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool const using_timer=timeout_index!=~0u;
|
||||
detail::timeout::remaining_time time_left(0);
|
||||
|
||||
do
|
||||
{
|
||||
if(!using_timer)
|
||||
{
|
||||
time_left=target_time.remaining_milliseconds();
|
||||
}
|
||||
|
||||
if(handle_count)
|
||||
{
|
||||
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
|
||||
if(notified_index<handle_count)
|
||||
{
|
||||
if(notified_index==wait_handle_index)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if(notified_index==timeout_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::win32::Sleep(time_left.milliseconds);
|
||||
}
|
||||
if(target_time.relative)
|
||||
{
|
||||
target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
|
||||
}
|
||||
}
|
||||
while(time_left.more);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
thread::id get_id() BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user