How to implement C++ Task Scheduler - c++

I Know the following code is not Task Scheduler Perhaps
However, trying to get your valuable comments in understanding the scheduler
I am trying to understand & come up with a bare minimum code which can be called as TaskScheduler.
I have the following code but am not sure if it suffices as scheduling.
Could someone provide the comments & code skeleton reference or links?
Thanks!!
#include <iostream>
#include <thread>
#include <future>
#include <queue>
#include <mutex>
#include <condition_variable>
using namespace std;
int factorial_loc(int val) {
int res = 1;
while(val>0) {
res *= val;
val--;
}
return res;
}
queue<packaged_task<int()>> q;
mutex mtx;
condition_variable cond;
void thread_1() {
unique_lock<mutex> ul(mtx);
cond.wait(ul, [](){
return !q.empty();
});
auto f = std::move(q.front());
q.pop();
f();
}
void run_packaged_task()
{
packaged_task<int(int)> t(factorial_loc);
packaged_task<int()> t2(std::bind(factorial_loc, 4));
future<int> f = t2.get_future();
thread t1(thread_1);
{
unique_lock<mutex> ul(mtx);
q.push(std::move(t2));
}
cond.notify_one();
cout<<"\n Res: "<<f.get();
t1.join();
}

I have the following code but am not sure if it suffices as scheduling.
Why not just do this?
void run_packaged_task()
{
cout << "\n Res: " << factorial_loc(4);
}
Maybe you think that my version of run_packaged_task() is not a scheduler. Well, OK. I don't think so either. But, as far as the caller can tell, my version does exactly the same as what your version does;
It computes the factorial of 4,
It writes the result to cout,
And then, only when that's done, it returns.
Your code contains some of the pieces of a scheduler; a thread, a queue, a data type that represents a task, but you don't use any of those pieces to do anything that looks like scheduling.
IMO, you need to think about what "scheduler" means. What do you expect a scheduler to do?
Should a scheduler execute each task as soon as possible? Or, if not, then when? How does the caller say when? How does the scheduler defer execution of the task until such time?
Should the caller have to wait until the task is completed? Should the caller have an option to wait?
I don't know exactly what you mean by "scheduler," but if my guess is correct, then it would have somewhat in common with a thread pool. Maybe you could get some traction if you start by searching for examples of how to implement a simplistic thread pool, and then think about how you could "improve" it to make a "scheduler."

Related

Two questions on std::condition_variables

I have been trying to figure out std::condition_variables and I am particularly confused by wait() and whether to use notify_all or notify_one.
First, I've written some code and attached it below. Here's a short explanation: Collection is a class that holds onto a bunch of Counter objects. These Counter objects have a Counter::increment() method, which needs to be called on all the objects, over and over again. To speed everything up, Collection also maintains a thread pool to distribute the work over, and sends out all the work with its Collection::increment_all() method.
These threads don't need to communicate with each other, and there are usually many more Counter objects than there are threads. It's fine if one thread processes more than Counters than others, just as long as all the work gets done. Adding work to the queue is easy and only needs to be done in the "main" thread. As far as I can see, the only bad thing that can happen is if other methods (e.g. Collection::printCounts) are allowed to be called on the counters in the middle of the work being done.
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <queue>
class Counter{
private:
int m_count;
public:
Counter() : m_count(0) {}
void increment() {
m_count ++;
}
int getCount() const { return m_count; }
};
class Collection{
public:
Collection(unsigned num_threads, unsigned num_counters)
: m_shutdown(false)
{
// start workers
for(size_t i = 0; i < num_threads; ++i){
m_threads.push_back(std::thread(&Collection::work, this));
}
// intsntiate counters
for(size_t j = 0; j < num_counters; ++j){
m_counters.emplace_back();
}
}
~Collection()
{
m_shutdown = true;
for(auto& t : m_threads){
if(t.joinable()){
t.join();
}
}
}
void printCounts() {
// wait for work to be done
std::unique_lock<std::mutex> lk(m_mtx);
m_work_complete.wait(lk); // q2: do I need a while lop?
// print all current counters
for(const auto& cntr : m_counters){
std::cout << cntr.getCount() << ", ";
}
std::cout << "\n";
}
void increment_all()
{
std::unique_lock<std::mutex> lock(m_mtx);
m_work_complete.wait(lock);
for(size_t i = 0; i < m_counters.size(); ++i){
m_which_counters_have_work.push(i);
}
}
private:
void work()
{
while(!m_shutdown){
bool action = false;
unsigned which_counter;
{
std::unique_lock<std::mutex> lock(m_mtx);
if(m_which_counters_have_work.size()){
which_counter = m_which_counters_have_work.front();
m_which_counters_have_work.pop();
action = true;
}else{
m_work_complete.notify_one(); // q1: notify_all
}
}
if(action){
m_counters[which_counter].increment();
}
}
}
std::vector<Counter> m_counters;
std::vector<std::thread> m_threads;
std::condition_variable m_work_complete;
std::mutex m_mtx;
std::queue<unsigned> m_which_counters_have_work;
bool m_shutdown;
};
int main() {
int num_threads = std::thread::hardware_concurrency()-1;
int num_counters = 10;
Collection myCollection(num_threads, num_counters);
myCollection.printCounts();
myCollection.increment_all();
myCollection.printCounts();
myCollection.increment_all();
myCollection.printCounts();
return 0;
}
I compile this on Ubuntu 18.04 with g++ -std=c++17 -pthread thread_pool.cpp -o tp && ./tp I think the code accomplishes all of those objectives, but a few questions remain:
I am using m_work_complete.wait(lk) to make sure the work is finished before I start printing all the new counts. Why do I sometimes see this written inside a while loop, or with a second argument as a lambda predicate function? These docs mention spurious wake ups. If a spurious wake up occurs, does that mean printCounts could prematurely print? If so, I don't want that. I just want to ensure the work queue is empty before I start using the numbers that should be there.
I am using m_work_complete.notify_all instead of m_work_complete.notify_one. I've read this thread, and I don't think it matters--only the main thread is going to be blocked by this. Is it faster to use notify_one just so the other threads don't have to worry about it?
std::condition_variable is not really a condition variable, it's more of a synchronization tool for reaching a certain condition. What that condition is is up to the programmer, and it should still be checked after each condition_variable wake-up, since it can wake-up spuriously, or "too early", when the desired condition isn't yet reached.
On POSIX systems, condition_variable::wait() delegates to pthread_cond_wait, which is susceptible to spurious wake-up (see "Condition Wait Semantics" in the Rationale section). On Linux, pthread_cond_wait is in turn implemented via a futex, which is again susceptible to spurious wake-up.
So yes you still need a flag (protected by the same mutex) or some other way to check that the work is actually complete. A convenient way to do this is by wrapping the check in a predicate and passing it to the wait() function, which would loop for you until the predicate is satisfied.
notify_all unblocks all threads waiting on the condition variable; notify_one unblocks just one (or at least one, to be precise). If there are more than one waiting threads, and they are equivalent, i.e. either one can handle the condition fully, and if the condition is sufficient to let just one thread continue (as in submitting a work unit to a thread pool), then notify_one would be more efficient since it won't unblock other threads unnecessarily for them to only notice no work to be done and going back to waiting. If you ever only have one waiter, then there would be no difference between notify_one and notify_all.
It's pretty simple: Use notify() when;
There is no reason why more than one thread needs to know about the event. (E.g., use notify() to announce the availability of an item that a worker thread will "consume," and thereby make the item unavailable to other workers)*AND*
There is no wrong thread that could be awakened. (E.g., you're probably safe if all of the threads are wait()ing in the same line of the same exact function.)
Use notify_all() in all other cases.

How to execute a function on a specific thread id in C++?

Is it possible I can invoke a function on a specific thread given the thread ID? I am currently on a different thread.
You need cooperation from the target thread; for instance, the target thread has to execute a loop at the top of which it waits on some sort of message box. Through that message box you give it a message that contains the function to be called and the arguments to use. Through the same mechanism, the function can produce a reply containing the result of the call.
But you can't just make a random thread that is running arbitrary code call your function. Although, never say never. There are tricks like, for instance, asynchronous POSIX signals and such: send a signal to a thread, which inspects some datum that tells it to call a function. That is confounded by the limitations as to what can be safely done out of a signal handler.
In a debugger, you can stop all the threads, then "switch" to a particular one and evaluate expressions in its context, including function calls. That is also an approach that would be inadvisable to integrate into production code; you have no idea what state a stopped thread is in to be able to safely and reliably do anything in that thread.
One possible solution is to make the worker threads execute based on tasks (functions),i.e you use a container to store functions you'd like the worker thread to execution, and the work thread's job is to execute functions in the container.
Here's an example, hope it helps.
#include <iostream>
#include <list>
#include <functional>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
using namespace std;
void foo() {
cout << "foo() is called" << endl;
}
template<typename T>
class TaskQueue {
public:
void enqueue(T&& task) {
unique_lock<mutex> l(m);
tasks.push_back(move(task));
cv.notify_one();
}
bool empty() { unique_lock<mutex> l(m); return tasks.empty(); }
void setStop() { stop = true; unique_lock<mutex> l(m); cv.notify_one(); }
void run() {
T t;
while (!stop) {
{
unique_lock<mutex> l(m);
cv.wait(l, [&] {return !tasks.empty() || stop;});
if (!tasks.empty()) {
t = move(tasks.front());
tasks.pop_front();
}
else
return;
}
t();
}
}
private:
atomic<bool> stop = false;
mutex m;
condition_variable cv;
list<T> tasks;
};
int main() {
TaskQueue<function<void(void)>> taskq;
thread t(&TaskQueue<function<void(void)>>::run, &taskq);
taskq.enqueue(foo);
taskq.enqueue(foo);
taskq.enqueue(foo);
while (!taskq.empty()) {}
taskq.setStop();
t.join();
}

thread that executes function calls from a main thread c++11

I want to implement a thread that can accept function pointers from a main thread and execute them serially. My idea was to use a struct that keeps the function pointer and its object and keep pushing it to a queue. This can be encapsulated in a class. The task thread can then pop from the queue and process it. I also need to synchronize it(so it doesnt block the main thread?), so I was thinking of using a semaphore. Although I have a decent idea of the structure of the program, I am having trouble coding this up, especially the threading and semaphore sync in C++11. It'd be great if someone can suggest an outline by which I can go about implementing this.
EDIT: The duplicate question answers the question about creating a thread pool. It looks like multiple threads are being created to do some work. I only need one thread that can queue function pointers and process them in the order they are received.
Check this code snippet, I have implemented without using a class though. See if it helps a bit. Conditional variable could be avoided here, but I want the reader thread to poll only when there is a signal from the writer so that CPU cycles in the reader won't be wasted.
#include <iostream>
#include <functional>
#include <mutex>
#include <thread>
#include <queue>
#include <chrono>
#include <condition_variable>
using namespace std;
typedef function<void(void)> task_t;
queue<task_t> tasks;
mutex mu;
condition_variable cv;
bool stop = false;
void writer()
{
while(!stop)
{
{
unique_lock<mutex> lock(mu);
task_t task = [](){ this_thread::sleep_for(chrono::milliseconds(100ms)); };
tasks.push(task);
cv.notify_one();
}
this_thread::sleep_for(chrono::milliseconds(500ms)); // writes every 500ms
}
}
void reader()
{
while(!stop)
{
unique_lock<mutex> lock(mu);
cv.wait(lock,[]() { return !stop;});
while( !tasks.empty() )
{
auto task = tasks.front();
tasks.pop();
lock.unlock();
task();
lock.lock();
}
}
}
int main()
{
thread writer_thread([]() { writer();} );
thread reader_thread([]() { reader();} );
this_thread::sleep_for(chrono::seconds(3s)); // main other task
stop = true;
writer_thread.join();
reader_thread.join();
}
Your problem has 2 parts. Storing the list of jobs and manipulating the jobs list in a threadsafe way.
For the first part, look into std::function, std::bind, and std::ref.
For the second part, this is similar to the producer/consumer problem. You can implement a semaphore using std::mutexand std::condition_variable.
There's a hint/outline. Now my full answer...
Step 1)
Store your function pointers in a queue of std::function.
std::queue<std::function<void()>>
Each element in the queue is a function that takes no arguments and returns void.
For functions that take arguments, use std::bind to bind the arguments.
void testfunc(int n);
...
int mynum = 5;
std::function<void()> f = std::bind(testfunction, mynum);
When f is invoked, i.e. f(), 5 will be passed as argument 1 to testfunc. std::bind copies mynum by value immediately.
You probably will want to be able to pass variables by reference as well. This is useful for getting results back from functions as well as passing in shared synchronization devices like semaphores and conditions. Use std::ref, the reference wrapper.
void testfunc2(int& n); // function takes n by ref
...
int a = 5;
std::function<void()> f = std::bind(testfunction, std::ref(a));
std::function and std::bind can work with any callables--functions, functors, or lambdas--which is pretty neat!
Step 2)
A worker thread dequeues while the queue is non-empty. Your code should look similar to the producer/consumer problem.
class AsyncWorker
{
...
public:
// called by main thread
AddJob(std::function<void()> f)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
m_queue.push(std::move(f));
++m_numJobs;
}
m_condition.notify_one(); // It's good style to call notify_one when not holding the lock.
}
private:
worker_main()
{
while(!m_exitCondition)
doJob();
}
void doJob()
{
std::function<void()> f;
{
std::unique_lock<std::mutex> lock(m_mutex);
while (m_numJobs == 0)
m_condition.wait(lock);
if (m_exitCondition)
return;
f = std::move(m_queue.front());
m_queue.pop();
--m_numJobs;
}
f();
}
...
Note 1: The synchronization code...with m_mutex, m_condition, and m_numJobs...is essentially what you have to use to implement a semaphore in C++'11. What I did here is more efficient than using a separate semaphore class because only 1 lock is locked. (A semaphore would have its own lock and you would still have to lock the shared queue).
Note 2: You can easily add additional worker threads.
Note 3: m_exitCondition in my example is an std::atomic<bool>
Actually setting up the AddJob function in a polymorphic way gets into C++'11 variadic templates and perfect forwarding...
class AsyncWorker
{
...
public:
// called by main thread
template <typename FUNCTOR, typename... ARGS>
AddJob(FUNCTOR&& functor, ARGS&&... args)
{
std::function<void()> f(std::bind(std::forward<FUNCTOR>(functor), std::forward<ARGS&&>(args)...));
{
std::lock_guard<std::mutex> lock(m_mutex);
m_queue.push(std::move(f));
++m_numJobs;
}
m_condition.notify_one(); // It's good style to call notify_one when not holding the lock.
}
I think it may work if you just used pass-by-value instead of using the forwarding references, but I haven't tested this, while I know the perfect forwarding works great. Avoiding perfect forwarding may make the concept slightly less confusing but the code won't be much different...

Change std::thread execution flow with signals in c++

I have a program starting an std::thread doing the following: sleep X, execute a function, terminate.
create std::thread(Xms, &func)
wait Xms
then do func()
end
I was wondering if I could for example send a signal to my std::thread in order to instantly break the sleep and do func, then quit.
Do I need to send the signal to std::thread::id in order to perform this?
my thread is launched this way, with a lambda function:
template<typename T, typename U>
void execAfter(T func, U params, const int ms)
{
std::thread thread([=](){
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
func(params);
});
thread.detach();
}
Using wait_for of std::condition_variable would be the way to go, if the thread model can't be changed. In the code snippet below, the use of the condition_variable is wrapped into a class of which objects have to be shared across the threads.
#include <iostream>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <chrono>
class BlockCondition
{
private:
mutable std::mutex m;
std::atomic<bool> done;
mutable std::condition_variable cv;
public:
BlockCondition()
:
m(),
done(false),
cv()
{
}
void wait_for(int duration_ms)
{
std::unique_lock<std::mutex> l(m);
int ms_waited(0);
while ( !done.load() && ms_waited < duration_ms )
{
auto t_0(std::chrono::high_resolution_clock::now());
cv.wait_for(l, std::chrono::milliseconds(duration_ms - ms_waited));
auto t_1(std::chrono::high_resolution_clock::now());
ms_waited += std::chrono::duration_cast<std::chrono::milliseconds>(t_1 - t_0).count();
}
}
void release()
{
std::lock_guard<std::mutex> l(m);
done.store(true);
cv.notify_one();
}
};
void delayed_func(BlockCondition* block)
{
block->wait_for(1000);
std::cout << "Hello actual work\n";
}
void abortSleepyFunction(BlockCondition* block)
{
block->release();
}
void test_aborted()
{
BlockCondition b();
std::thread delayed_thread(delayed_func, &b);
abortSleepyFunction(&b);
delayed_thread.join();
}
void test_unaborted()
{
BlockCondition b();
std::thread delayed_thread(delayed_func, &b);
delayed_thread.join();
}
int main()
{
test_aborted();
test_unaborted();
}
Note that there might be spurious wakeups that abort the wait call prematurely. To account for that, we count the milliseconds actually waited and continue waiting until the done flag is set.
As was pointed out in the comments, this wasn't the smartest approach for solving your problem in the first place. As implementing a proper interruption mechanism is quite complex and extremely easy to get wrong, here are suggestions for a workaround:
Instead of sleeping for the whole timeout, simply loop over a sleep of fixed small size (e.g. 10 milliseconds) until the desired duration has elapsed. After each sleep you check an atomic flag whether interruption was requested. This is a dirty solution, but is the quickest to pull of.
Alternatively, supply each thread with a condition_variable and do a wait on it instead of doing the this_thread::sleep. Notify the condition variable to indicate the request for interruption. You will probably still want an additional flag to protect against spurious wakeups so you don't accidentally return too early.
Ok, to figure this out I found a new implementation, it's inspired by all your answers so thanks a lot.
First I am gonna do a BombHandler item, in the main Game item. It will have a an attribute containing all the Bomb items.
This BombHandler will be a singleton, containing a timerLoop() function who will execute in a thread (This way I only use ONE thread for xxx bombs, way more effective)
The timerLoop() will usleep(50) then pass through the whole std::list elements and call Bomb::incrTimer() who will increment their internal _timer attribute by 10ms indefinitely, and check bombs who have to explode.
When they reach 2000ms for instance, BombHandler.explode() will be called, exploding the bomb and deleting it.
If another bomb is in range Bomb::touchByFire() will be called, and set the internal attribute of Bomb, _timer, to TIME_TO_EXPLODE (1950ms).
Then it will be explode 50ms later by BombHandler::explode().
Isn't this a nice solution?
Again, thanks for your answers! Hope this can help.

Creating a lock that preserves the order of locking attempts in C++11

Is there a way to ensure that blocked threads get woken up in the same order as they got blocked? I read somewhere that this would be called a "strong lock" but I found no resources on that.
On Mac OS X one can design a FIFO queue that stores all the thread ids of the blocked threads and then use the nifty function pthread_cond_signal_thread_np() to wake up one specific thread - which is obviously non-standard and non-portable.
One way I can think of is to use a similar queue and at the unlock() point send a broadcast() to all threads and have them check which one is the next in line.
But this would induce lots of overhead.
A way around the problem would be to issue packaged_task's to the queue and have it process them in order. But that seems more like a workaround to me than a solution.
Edit:
As pointed out by the comments, this question may sound irrelevant, since there is in principle no guaranteed ordering of locking attempts.
As a clarification:
I have something I call a ConditionLockQueue which is very similar to the NSConditionLock class in the Cocoa library, but it maintains a FIFO queue of blocked threads instead of a more-or-less random pool.
Essentially any thread can "line up" (with or without the requirement of a specific 'condition' - a simple integer value - to be met). The thread is then placed on the queue and blocks until it is the frontmost element in the queue whose condition is met.
This provides a very flexible way of synchronization and I have found it very helpful in my program.
Now what I really would need is a way to wake up a specific thread with a specific id.
But these problems are almost alike.
Its pretty easy to build a lock object that uses numbered tickets to insure that its completely fair (lock is granted in the order threads first tried to acquire it):
#include <mutex>
#include <condition_variable>
class ordered_lock {
std::condition_variable cvar;
std::mutex cvar_lock;
unsigned int next_ticket, counter;
public:
ordered_lock() : next_ticket(0), counter(0) {}
void lock() {
std::unique_lock<std::mutex> acquire(cvar_lock);
unsigned int ticket = next_ticket++;
while (ticket != counter)
cvar.wait(acquire);
}
void unlock() {
std::unique_lock<std::mutex> acquire(cvar_lock);
counter++;
cvar.notify_all();
}
};
edit
To fix Olaf's suggestion:
#include <mutex>
#include <condition_variable>
#include <queue>
class ordered_lock {
std::queue<std::condition_variable *> cvar;
std::mutex cvar_lock;
bool locked;
public:
ordered_lock() : locked(false) {};
void lock() {
std::unique_lock<std::mutex> acquire(cvar_lock);
if (locked) {
std::condition_variable signal;
cvar.emplace(&signal);
signal.wait(acquire);
} else {
locked = true;
}
}
void unlock() {
std::unique_lock<std::mutex> acquire(cvar_lock);
if (cvar.empty()) {
locked = false;
} else {
cvar.front()->notify_one();
cvar.pop();
}
}
};
I tried Chris Dodd solution
https://stackoverflow.com/a/14792685/4834897
but the compiler returned errors because queues allows only standard containers that are capable.
while references (&) are not copyable as you can see in the following answer by Akira Takahashi :
https://stackoverflow.com/a/10475855/4834897
so I corrected the solution using reference_wrapper which allows copyable references.
EDIT: #Parvez Shaikh suggested small alteration to make the code more readable by moving cvar.pop() after signal.wait() in lock() function
#include <mutex>
#include <condition_variable>
#include <queue>
#include <atomic>
#include <vector>
#include <functional> // std::reference_wrapper, std::ref
using namespace std;
class ordered_lock {
queue<reference_wrapper<condition_variable>> cvar;
mutex cvar_lock;
bool locked;
public:
ordered_lock() : locked(false) {}
void lock() {
unique_lock<mutex> acquire(cvar_lock);
if (locked) {
condition_variable signal;
cvar.emplace(std::ref(signal));
signal.wait(acquire);
cvar.pop();
} else {
locked = true;
}
}
void unlock() {
unique_lock<mutex> acquire(cvar_lock);
if (cvar.empty()) {
locked = false;
} else {
cvar.front().get().notify_one();
}
}
};
Another option is to use pointers instead of references, but it seems less safe.
Are we asking the right questions on this thread??? And if so: are they answered correctly???
Or put another way:
Have I completely misunderstood stuff here??
Edit Paragraph: It seems StatementOnOrder (see below) is false. See link1 (C++ threads etc. under Linux are ofen based on pthreads), and link2 (mentions current scheduling policy as the determining factor) -- Thanks to Cubbi from cppreference (ref). See also link, link, link, link. If the statement is false, then the method of pulling an atomic (!) ticket, as shown in the code below, is probably to be preferred!!
Here goes...
StatementOnOrder: "Multiple threads that run into a locked mutex and thus "go to sleep" in a particular order, will afterwards aquire ownership of the mutex and continue on in the same order."
Question: Is StatementOnOrder true or false ???
void myfunction() {
std::lock_guard<std::mutex> lock(mut);
// do something
// ...
// mutex automatically unlocked when leaving funtion.
}
I'm asking this because all code examples on this page to date, seem to be either:
a) a waste (if StatementOnOrder is true)
or
b) seriously wrong (if StatementOnOrder is false).
So why do a say that they might be "seriously wrong", if StatementOnOrder is false?
The reason is that all code examples think they're being super-smart by utilizing std::condition_variable, but are actually using locks before that, which will (if StatementOnOrder is false) mess up the order!!!
Just search this page for std::unique_lock<std::mutex>, to see the irony.
So if StatementOnOrder is really false, you cannot run into a lock, and then handle tickets and condition_variables stuff after that. Instead, you'll have to do something like this: pull an atomic ticket before running into any lock!!!
Why pull a ticket, before running into a lock? Because here we're assuming StatementOnOrder to be false, so any ordering has to be done before the "evil" lock.
#include <mutex>
#include <thread>
#include <limits>
#include <atomic>
#include <cassert>
#include <condition_variable>
#include <map>
std::mutex mut;
std::atomic<unsigned> num_atomic{std::numeric_limits<decltype(num_atomic.load())>::max()};
unsigned num_next{0};
std::map<unsigned, std::condition_variable> mapp;
void function() {
unsigned next = ++num_atomic; // pull an atomic ticket
decltype(mapp)::iterator it;
std::unique_lock<std::mutex> lock(mut);
if (next != num_next) {
auto it = mapp.emplace(std::piecewise_construct,
std::forward_as_tuple(next),
std::forward_as_tuple()).first;
it->second.wait(lock);
mapp.erase(it);
}
// THE FUNCTION'S INTENDED WORK IS NOW DONE
// ...
// ...
// THE FUNCTION'S INDENDED WORK IS NOW FINISHED
++num_next;
it = mapp.find(num_next); // this is not necessarily mapp.begin(), since wrap_around occurs on the unsigned
if (it != mapp.end()) {
lock.unlock();
it->second.notify_one();
}
}
The above function guarantees that the order is executed according to the atomic ticket that is pulled. (Edit: using boost's intrusive map, an keeping condition_variable on the stack (as a local variable), would be a nice optimization, which can be used here, to reduce free-store usage!)
But the main question is:
Is StatementOnOrder true or false???
(If it is true, then my code example above is a also waste, and we can just use a mutex and be done with it.)
I wish somebody like Anthony Williams would check out this page... ;)