intel openTBB task arenas behaviour - c++

Is it guaranteed that all tasks in the task_arena will be executed on the same threads set? for example I would have a rendering thread to call opengl API. Can I use something like that? Documentation isn't clear in that/
auto rendering_arena = tbb::task_arena(1, 0);
rendering_arena.execute([](){
while (window_available) {
// draw something
}
});
If i have two arenas, can their threads sets be intersected? Or the work isn't balanced between arenas? So, can I think of arenas as different schedulers?
I tried to write simple example. There it is:
# include <tbb/tbb.h>
# include <iostream>
# include <sstream>
# include <thread>
#include <utility>
void task(const std::string& prefix) {
using namespace std::chrono_literals;
std::this_thread::sleep_for(1s);
std::stringstream out;
out << prefix << " on thread " << std::this_thread::get_id() << '\n';
std::cout << out.str();
}
struct environment {
tbb::task_arena arena;
tbb::task_group group;
std::string env_prefix;
explicit environment(std::string prefix, int concurrency)
: env_prefix(std::move(prefix)),
arena(concurrency, 0),
group() {}
void run(std::size_t n) {
arena.execute([n, this]() {
for (std::size_t i = 0; i < n; ++i) {
group.run([i, this]() {
task(env_prefix + "::" + std::to_string(i));
});
}
});
}
void wait() {
arena.execute([this]() {
group.wait();
});
}
};
int main() {
auto begin = tbb::tick_count::now();
auto env1 = environment("1", 1);
auto env2 = environment("2", 1);
auto env3 = environment("3", 5);
env1.run(10);
env2.run(10);
env3.run(10);
std::cout << "main continue\n";
env1.wait();
env2.wait();
auto end = tbb::tick_count::now();
std::cout << "full time: " << (end - begin).seconds();
return 0;
}
And that works as I expect. possible output:
main continue
3::3 on thread 12564
3::9 on thread 12052
1::9 on thread 2712
3::1 on thread 6200
3::2 on thread 5780
2::0 on thread 14016
3::0 on thread 2860
3::8 on thread 12052
1::8 on thread 2712
3::4 on thread 12564
3::7 on thread 2860
2::1 on thread 14016
3::6 on thread 5780
3::5 on thread 6200
2::2 on thread 14016
1::7 on thread 2712
1::6 on thread 2712
2::3 on thread 14016
1::5 on thread 2712
2::4 on thread 14016
1::4 on thread 2712
2::5 on thread 14016
1::3 on thread 2712
2::6 on thread 14016
1::2 on thread 2712
2::7 on thread 14016
1::1 on thread 2712
2::8 on thread 14016
1::0 on thread 2712
2::9 on thread 14016
full time: 10.0846

I got the answer in that issue. In short:
Is it guaranteed that all tasks
in the task_arena will be
executed on the same threads set?
The short answer is no. Threads might migrate between arenas.
If i have two arenas, can their threads sets be intersected?
When there is no available work in arenas threads will leave them and block(sleep) until further work submission.
Once new work will be submitted threads might join to arenas in unpredictable manner.

Related

How to let thread wait for specific other thread to unlock data c++

Lets say I have one thread that continuously updates a certain object. During the update, the object must be locked for thread safety.
Now the second thread is more of an event kind of operation. If such a thread is spawned, I'd like the running update to finish it's call and then immediately perform the event operation.
What I absolutely want to avoid is a situation where the event thread needs to wait until it gets lucky to be given computation time at a specific time the update thread doesn't lock up the data it needs to access.
Is there any way I could use the threading/mutex tools in c++ to accomplish this? Or should I save the to-be-done operation in an unlocked var and perform the operation on the update thread?
//// System.h
#pragma once
#include <mutex>
#include <iostream>
#include <chrono>
#include <thread>
class System {
private:
int state = 0;
std::mutex mutex;
public:
void update();
void reset(int e);
};
//////// System.cpp
#include "System.h"
void System::update() {
std::lock_guard<std::mutex> guard(mutex);
state++;
std::cout << state << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void System::reset(int e) {
std::lock_guard<std::mutex> guard(mutex);
state = e;
std::cout << state << std::endl;
}
////// ThreadTest.h
#pragma once
#include <iostream>
#include "System.h"
void loop_update(System& system);
void reset_system(System& system);
int main();
////// ThreadTest.cpp
#include "ThreadTest.h"
void loop_update(System& system) {
while (true) system.update();
};
void reset_system(System& system) {
system.reset(0);
};
int main()
{
System system;
std::thread t1 = std::thread(loop_update, std::ref(system));
int reset = 0;
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(10));
std::cout << "Reset" << std::endl;
reset_system(system);
}
}
Example gives following output. You can clearly see a huge delay in the actual update.
1
...
10
Reset
11
...
16
0
1
...
10
Reset
11
...
43
0
1
If I understand you correctly, you have 2 threads using the same mutex. However, you want one thread to get a higher preference than the other to get the actual lock.
As far as I know, there ain't a way to ensure preference using the native tools. You can work around it, if you don't mind the code of both threads knowing about it.
For example:
std::atomic<int> shouldPriorityThreadRun{0};
auto priorityThreadCode = [&shouldPriorityThreadRun](){
++shouldPriorityThreadRun;
auto lock = std::unique_lock{mutex};
doMyStuff();
--shouldPriorityThreadRun;
};
auto backgroundThreadCode = [&shouldPriorityThreadRun](){
while (true)
{
if (shouldPriorityThreadRun == 0)
{
auto lock = std::unique_lock{mutex};
doBackgroundStuff();
}
else
std::this_thread::yield();
}
};
If you have multiple priority threads, those can't have priority over each other.
If you don't like the yield, you could do fancier stuff with std::condition_variable, so you can inform other threads that the mutex is available. However, I believe it's good enough.
it should already work with your current approach.
The mutex is locking concurrent access to your data, so you can lock it within the first thread to update the data.
If the event routine / your second thread comes to execution, it always has to check if the mutex is unlocked. If the mutex is unlocked - and only then, you can lock the mutex and perform the tasks of the second thread.
If I understand your code correctly (i am not a c++ expert), the std::lock_guard<std::mutex> guard(mutex); seems to be locking the mutex the entire time of the update function...
And therefore other threads merely have time to access the mutex.
When the update thread finish the job, it needs to unlock the mutex before entering the sleep state, then the reset thread could have a chance to take the lock without any delay. I also tried running your codes on my machine and observe it's still waiting for the lock. I don't know when it gets lucky to take the lock. I think in this case it's an UB
2
3
4
5
6
7
8
9
10
Reset
11
12
13
14
15
16
17
18...
void System::update() {
mutex.lock();
state++;
std::cout << state << std::endl;
mutex.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void System::reset(int e) {
mutex.lock();
state = e;
std::cout << state << std::endl;
mutex.unlock();
}

boost::fiber scheduling - when and how

According to the documentation
the currently-running fiber retains control until it invokes some
operation that passes control to the manager
I can think about only one operation - boost::this_fiber::yield which may cause control switch from fiber to fiber. However, when I run something like
bf::fiber([](){std::cout << "Bang!" << std::endl;}).detach();
bf::fiber([](){std::cout << "Bung!" << std::endl;}).detach();
I get output like
Bang!Bung!
\n
\n
Which means control was passed between << operators from one fiber to another. How it could happen? Why? What is the general definition of controll passing from fiber to fiber in the context of boost::fiber library?
EDIT001:
Cant get away without code:
#include <boost/fiber/fiber.hpp>
#include <boost/fiber/mutex.hpp>
#include <boost/fiber/barrier.hpp>
#include <boost/fiber/algo/algorithm.hpp>
#include <boost/fiber/algo/work_stealing.hpp>
namespace bf = boost::fibers;
class GreenExecutor
{
std::thread worker;
bf::condition_variable_any cv;
bf::mutex mtx;
bf::barrier barrier;
public:
GreenExecutor() : barrier {2}
{
worker = std::thread([this] {
bf::use_scheduling_algorithm<bf::algo::work_stealing>(2);
// wait till all threads joining the work stealing have been registered
barrier.wait();
mtx.lock();
// suspend main-fiber from the worker thread
cv.wait(mtx);
mtx.unlock();
});
bf::use_scheduling_algorithm<bf::algo::work_stealing>(2);
// wait till all threads have been registered the scheduling algorithm
barrier.wait();
}
template<typename T>
void PostWork(T&& functor)
{
bf::fiber {std::move(functor)}.detach();
}
~GreenExecutor()
{
cv.notify_all();
worker.join();
}
};
int main()
{
GreenExecutor executor;
std::this_thread::sleep_for(std::chrono::seconds(1));
int i = 0;
for (auto j = 0ul; j < 10; ++j) {
executor.PostWork([idx {++i}]() {
auto res = pow(sqrt(sin(cos(tan(idx)))), M_1_PI);
std::cout << idx << " - " << res << std::endl;
});
}
while (true) {
boost::this_fiber::yield();
}
return 0;
}
Output
2 - 1 - -nan
0.503334 3 - 4 - 0.861055
0.971884 5 - 6 - 0.968536
-nan 7 - 8 - 0.921959
0.9580699
- 10 - 0.948075
0.961811
Ok, there were a couple of things I missed, first, my conclusion was based on misunderstanding of how stuff works in boost::fiber
The line in the constructor mentioned in the question
bf::use_scheduling_algorithm<bf::algo::work_stealing>(2);
was installing the scheduler in the thread where the GreenExecutor instance was created (in the main thread) so, when launching two worker fibers I was actually initiating two threads which are going to process submitted fibers which in turn would process these fibers asynchronously thus mixing the std::cout output. No magic, everything works as expected, the boost::fiber::yield still is the only option to pass control from one fiber to another

C++ thread that starts several threads

I am trying to do a program that has to run 2 tasks periodically.
That is, for example, run task 1 every 10 seconds, and run task 2 every 20 seconds.
What I am thinking is to create two threads, each one with a timer. Thread 1 launches a new thread with task 1 every 10 seconds. and Thread 2 launches a new thread with task 2 every 20 seconds.
My doubt is, how to launch a new task 1 if the previous task 1 hasn't finished?
while (true)
{
thread t1 (task1);
this_thread::sleep_for(std::chrono::seconds(10));
t1.join();
}
I was trying this, but this way it will only launch a new task 1 when the previous one finishes.
EDIT:
Basically I want to implement a task scheduler.
Run task1 every X seconds.
Run task2 every Y seconds.
I was thinking in something like this:
thread t1 (timer1);
thread t2 (timer2);
void timer1()
{
while (true)
{
thread t (task1);
t.detach()
sleep(X);
}
}
the same for timer2 and task2
Perhaps you could create a periodic_task handler that is responsible for scheduling one task every t seconds. And then you can launch a periodic_task with a specific function and time duration from anywhere you want to in your program.
Below I've sketched something out. One valid choice is to detach the thread and let it run forever. Another is to include cancellation to allow the parent thread to cancel/join. I've included functionality to allow the latter (though you could still just detach/forget).
#include <condition_variable>
#include <functional>
#include <iostream>
#include <mutex>
#include <thread>
class periodic_task
{
std::chrono::seconds d_;
std::function<void()> task_;
std::mutex mut_;
std::condition_variable cv_;
bool cancel_{false};
public:
periodic_task(std::function<void()> task, std::chrono::seconds s)
: d_{s}
, task_(std::move(task))
{}
void
operator()()
{
std::unique_lock<std::mutex> lk{mut_};
auto until = std::chrono::steady_clock::now();
while (true)
{
while (!cancel_ && std::chrono::steady_clock::now() < until)
cv_.wait_until(lk, until);
if (cancel_)
return;
lk.unlock();
task_();
lk.lock();
until += d_;
}
}
void cancel()
{
std::unique_lock<std::mutex> lk{mut_};
cancel_ = true;
cv_.notify_one();
}
};
void
short_task()
{
std::cerr << "short\n";
}
void
long_task(int i, const std::string& message)
{
std::cerr << "long " << message << ' ' << i << '\n';
}
int
main()
{
using namespace std::chrono_literals;
periodic_task task_short{short_task, 7s};
periodic_task task_long{[](){long_task(5, "Hi");}, 13s};
std::thread t1{std::ref(task_short)};
std::this_thread::sleep_for(200ms);
std::thread t2{std::ref(task_long)};
std::this_thread::sleep_for(1min);
task_short.cancel();
task_long.cancel();
t1.join();
t2.join();
}
You want to avoid using thread::join() it, by definition, waits for the thread to finish. Instead, use thread::detach before sleeping, so it doesn't need to wait.
I'd suggest reading up on it http://www.cplusplus.com/reference/thread/thread/detach/

std::condition_variable not properly wakes up after std::condition_variable::notify_all() from other thread

This code is simplification of real project code. Main thread create worker thread and wait with std::condition_variable for worker thread really started. In code below std::condition_variable wakes up after current_thread_state becomes "ThreadState::Stopping" - this is the second notification from worker thread, that is the main thread did not wake up after the first notification, when current_thread_state becomes "ThreadState::Starting". The result was deadlock. Why this happens? Why std::condition_variable not wake up after first thread_event.notify_all()?
int main()
{
std::thread thread_var;
struct ThreadState {
enum Type { Stopped, Started, Stopping };
};
ThreadState::Type current_thread_state = ThreadState::Stopped;
std::mutex thread_mutex;
std::condition_variable thread_event;
while (true) {
{
std::unique_lock<std::mutex> lck(thread_mutex);
thread_var = std::move(std::thread([&]() {
{
std::unique_lock<std::mutex> lck(thread_mutex);
cout << "ThreadFunction() - step 1\n";
current_thread_state = ThreadState::Started;
}
thread_event.notify_all();
// This code need to disable output to console (simulate some work).
cout.setstate(std::ios::failbit);
cout << "ThreadFunction() - step 1 -> step 2\n";
cout.clear();
{
std::unique_lock<std::mutex> lck(thread_mutex);
cout << "ThreadFunction() - step 2\n";
current_thread_state = ThreadState::Stopping;
}
thread_event.notify_all();
}));
while (current_thread_state != ThreadState::Started) {
thread_event.wait(lck);
}
}
if (thread_var.joinable()) {
thread_var.join();
current_thread_state = ThreadState::Stopped;
}
}
return 0;
}
Once you call the notify_all method, your main thread and your worker thread (after doing its work) both try to get a lock on the thread_mutex mutex. If your work load is insignificant, like in your example, the worker thread is likely to get the lock before the main thread and sets the state back to ThreadState::Stopped before the main thread ever reads it. This results in a dead lock.
Try adding a significant work load, e.g.
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
to the worker thread. Dead locks are far less likely now. Of course, this is not a fix for your problem. This is just for illustrating the problem.
You have two threads racing: one writes values of current_thread_state twice, another reads the value of current_thread_state once.
It is indeterminate whether the sequence of events is write-write-read or write-read-write as you expect, both are valid executions of your application.

How to give priority to privileged thread in mutex locking?

First of all: I am completely a newbie in mutex/multithread programming, so
sorry for any error in advance...
I have a program that runs multiple threads. The threads (usually one per
cpu core) do a lot of
calculation and "thinking" and then sometimes they decide to call a
particular (shared) method that updates some statistics.
The concurrency on statistics updates is managed through the use of a mutex:
stats_mutex.lock();
common_area->update_thread_stats( ... );
stats_mutex.unlock();
Now to the problem.
Of all those threads there is one particular thread that need almost
realtime priority, because it's the only thread that actually operates.
With "almost realtime priority" I mean:
Let's suppose thread t0 is the "privileged one" and t1....t15 are the normal
ones.What happens now is:
Thread t1 acquires lock.
Thread t2, t3, t0 call the lock() method and wait for it to succeed.
Thread t1 calls unlock()
One (at random, as far as i know) of the threads t2, t3, t0 succeeds in acquiring
the lock, and the other ones continue to wait.
What I need is:
Thread t1 acquire lock.
Thread t2, t3, t0 call the lock() method and wait for it to succeed.
Thread t1 calls unlock()
Thread t0 acquires lock since it's privileged
So, what's the best (possibly simplest) method to do this thing?
What I was thinking is to have a bool variable called
"privileged_needs_lock".
But I think I need another mutex to manage access to this variable... I dont
know if this is the right way...
Additional info:
my threads use C++11 (as of gcc 4.6.3)
code needs to run on both Linux and Windows (but tested only on Linux at the moment).
performance on locking mechanism is not an issue (my performance problem are in internal thread calculations, and thread number will always be low, one or two per cpu core at maximum)
Any idea is appreciated.
Thanks
The below solution works (three mutex way):
#include <thread>
#include <iostream>
#include <mutex>
#include "unistd.h"
std::mutex M;
std::mutex N;
std::mutex L;
void lowpriolock(){
L.lock();
N.lock();
M.lock();
N.unlock();
}
void lowpriounlock(){
M.unlock();
L.unlock();
}
void highpriolock(){
N.lock();
M.lock();
N.unlock();
}
void highpriounlock(){
M.unlock();
}
void hpt(const char* s){
using namespace std;
//cout << "hpt trying to get lock here" << endl;
highpriolock();
cout << s << endl;
sleep(2);
highpriounlock();
}
void lpt(const char* s){
using namespace std;
//cout << "lpt trying to get lock here" << endl;
lowpriolock();
cout << s << endl;
sleep(2);
lowpriounlock();
}
int main(){
std::thread t0(lpt,"low prio t0 working here");
std::thread t1(lpt,"low prio t1 working here");
std::thread t2(hpt,"high prio t2 working here");
std::thread t3(lpt,"low prio t3 working here");
std::thread t4(lpt,"low prio t4 working here");
std::thread t5(lpt,"low prio t5 working here");
std::thread t6(lpt,"low prio t6 working here");
std::thread t7(lpt,"low prio t7 working here");
//std::cout << "All threads created" << std::endl;
t0.join();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
return 0;
}
Tried the below solution as suggested but it does not work (compile with " g++ -std=c++0x -o test test.cpp -lpthread"):
#include <thread>
#include <mutex>
#include "time.h"
#include "pthread.h"
std::mutex l;
void waiter(){
l.lock();
printf("Here i am, waiter starts\n");
sleep(2);
printf("Here i am, waiter ends\n");
l.unlock();
}
void privileged(int id){
usleep(200000);
l.lock();
usleep(200000);
printf("Here i am, privileged (%d)\n",id);
l.unlock();
}
void normal(int id){
usleep(200000);
l.lock();
usleep(200000);
printf("Here i am, normal (%d)\n",id);
l.unlock();
}
int main(){
std::thread tw(waiter);
std::thread t1(normal,1);
std::thread t0(privileged,0);
std::thread t2(normal,2);
sched_param sch;
int policy;
pthread_getschedparam(t0.native_handle(), &policy, &sch);
sch.sched_priority = -19;
pthread_setschedparam(t0.native_handle(), SCHED_FIFO, &sch);
pthread_getschedparam(t1.native_handle(), &policy, &sch);
sch.sched_priority = 18;
pthread_setschedparam(t1.native_handle(), SCHED_FIFO, &sch);
pthread_getschedparam(t2.native_handle(), &policy, &sch);
sch.sched_priority = 18;
pthread_setschedparam(t2.native_handle(), SCHED_FIFO, &sch);
tw.join();
t1.join();
t0.join();
t2.join();
return 0;
}
I can think of three methods using only threading primitives:
Triple mutex
Three mutexes would work here:
data mutex ('M')
next-to-access mutex ('N'), and
low-priority access mutex ('L')
Access patterns are:
Low-priority threads: lock L, lock N, lock M, unlock N, { do stuff }, unlock M, unlock L
High-priority thread: lock N, lock M, unlock N, { do stuff }, unlock M
That way the access to the data is protected, and the high-priority thread can get ahead of the low-priority threads in access to it.
Mutex, condition variable, atomic flag
The primitive way to do this is with a condition variable and an atomic:
Mutex M;
Condvar C;
atomic bool hpt_waiting;
Data access patterns:
Low-priority thread: lock M, while (hpt_waiting) wait C on M, { do stuff }, broadcast C, unlock M
High-priority thread: hpt_waiting := true, lock M, hpt_waiting := false, { do stuff }, broadcast C, unlock M
Mutex, condition variable, two non-atomic flag
Alternatively you can use two non-atomic bools with a condvar; in this technique the mutex/condvar protects the flags, and the data is protected not by a mutex but by a flag:
Mutex M;
Condvar C;
bool data_held, hpt_waiting;
Low-priority thread: lock M, while (hpt_waiting or data_held) wait C on M, data_held := true, unlock M, { do stuff }, lock M, data_held := false, broadcast C, unlock M
High-priority thread: lock M, hpt_waiting := true, while (data_held) wait C on M, data_held := true, unlock M, { do stuff }, lock M, data_held := false, hpt_waiting := false, broadcast C, unlock M
Put requesting threads on a 'priority queue'. The privileged thread can get first go at the data when it's free.
One way to do this would be withan array of ConcurrentQueues[privilegeLevel], a lock and some events.
Any thread that wants at the data enters the lock. If the data is free, (boolean), it gets the data object and exits the lock. If the data is in use by another thread, the requesting thread pushes an event onto one of the concurrent queues, depending on its privilege level, exits the lock and waits on the event.
When a thread wants to release its ownership of the data object, it gets the lock and iterates the array of ConcurrentQueues from the highest-privilege end down, looking for an event, (ie queue count>0). If it finds one, it signals it and exits the lock, if not, it sets the 'dataFree' boolean and and exits the lock.
When a thread waiting on an event for access to the data is made ready, it may access the data object.
I thnk that should work. Please, other developers, check this design and see if you can think of any races etc? I'm still suffering somewhat from 'hospitality overload' after a trip to CZ..
Edit - probably don't even need concurrent queues because of the explicit lock across them all. Any old queue would do.
#include <thread>
#include <mutex>
#include <condition_variable>
#include <cassert>
class priority_mutex {
std::condition_variable cv_;
std::mutex gate_;
bool locked_;
std::thread::id pr_tid_; // priority thread
public:
priority_mutex() : locked_(false) {}
~priority_mutex() { assert(!locked_); }
priority_mutex(priority_mutex&) = delete;
priority_mutex operator=(priority_mutex&) = delete;
void lock(bool privileged = false) {
const std::thread::id tid = std::this_thread::get_id();
std::unique_lock<decltype(gate_)> lk(gate_);
if (privileged)
pr_tid_ = tid;
cv_.wait(lk, [&]{
return !locked_ && (pr_tid_ == std::thread::id() || pr_tid_ == tid);
});
locked_ = true;
}
void unlock() {
std::lock_guard<decltype(gate_)> lk(gate_);
if (pr_tid_ == std::this_thread::get_id())
pr_tid_ = std::thread::id();
locked_ = false;
cv_.notify_all();
}
};
NOTICE: This priority_mutex provides unfair thread scheduling. If privileged thread acquires the lock frequently, other non-privileged threads may almost not scheduled.
Usage example:
#include <mutex>
priority_mutex mtx;
void privileged_thread()
{
//...
{
mtx.lock(true); // acquire 'priority lock'
std::unique_lock<decltype(mtx)> lk(mtx, std::adopt_lock);
// update shared state, etc.
}
//...
}
void normal_thread()
{
//...
{
std::unique_lock<decltype(mtx)> lk(mtx); // acquire 'normal lock'
// do something
}
//...
}
On linux you can check this man: pthread_setschedparam and also man sched_setscheduler
pthread_setschedparam(pthread_t thread, int policy,
const struct sched_param *param);
Check this also for c++2011:
http://msdn.microsoft.com/en-us/library/system.threading.thread.priority.aspx#Y78
pthreads has thread priorities:
pthread_setschedprio( (pthread_t*)(&mThreadId), wpri );
If multiple threads are sleeping waiting in a lock, the scheduler will wake the highest priority thread first.
Try something like the following. You could make the class a thread-safe singleton and you could even make it a functor.
#include <pthread.h>
#include <semaphore.h>
#include <map>
class ThreadPrioFun
{
typedef std::multimap<int, sem_t*> priomap_t;
public:
ThreadPrioFun()
{
pthread_mutex_init(&mtx, NULL);
}
~ThreadPrioFun()
{
pthread_mutex_destroy(&mtx);
}
void fun(int prio, sem_t* pSem)
{
pthread_mutex_lock(&mtx);
bool bWait = !(pm.empty());
priomap_t::iterator it = pm.insert(std::pair<int, sem_t*>(prio, pSem) );
pthread_mutex_unlock(&mtx);
if( bWait ) sem_wait(pSem);
// do the actual job
// ....
//
pthread_mutex_lock(&mtx);
// done, remove yourself
pm.erase(it);
if( ! pm.empty() )
{
// let next guy run:
sem_post((pm.begin()->second));
}
pthread_mutex_unlock(&mtx);
}
private:
pthread_mutex_t mtx;
priomap_t pm;
};
Since thread priorities isn't working for you:
Create 2 mutexes, a regular lock and a priority lock.
Regular threads must first lock the normal lock, and then the priority lock. The priority thread only has to lock the priority lock:
Mutex mLock;
Mutex mPriLock;
doNormal()
{
mLock.lock();
pthread_yield();
doPriority();
mLock.unlock();
}
doPriority()
{
mPriLock.lock();
doStuff();
mPriLock.unlock();
}
Modified slightly ecatmur answer, adding a 4th mutex to handle multiple high priority threads contemporaneously (note that this was not required in my original question):
#include <thread>
#include <iostream>
#include "unistd.h"
std::mutex M; //data access mutex
std::mutex N; // 'next to access' mutex
std::mutex L; //low priority access mutex
std::mutex H; //hptwaiting int access mutex
int hptwaiting=0;
void lowpriolock(){
L.lock();
while(hptwaiting>0){
N.lock();
N.unlock();
}
N.lock();
M.lock();
N.unlock();
}
void lowpriounlock(){
M.unlock();
L.unlock();
}
void highpriolock(){
H.lock();
hptwaiting++;
H.unlock();
N.lock();
M.lock();
N.unlock();
}
void highpriounlock(){
M.unlock();
H.lock();
hptwaiting--;
H.unlock();
}
void hpt(const char* s){
using namespace std;
//cout << "hpt trying to get lock here" << endl;
highpriolock();
cout << s << endl;
usleep(30000);
highpriounlock();
}
void lpt(const char* s){
using namespace std;
//cout << "lpt trying to get lock here" << endl;
lowpriolock();
cout << s << endl;
usleep(30000);
lowpriounlock();
}
int main(){
std::thread t0(lpt,"low prio t0 working here");
std::thread t1(lpt,"low prio t1 working here");
std::thread t2(hpt,"high prio t2 working here");
std::thread t3(lpt,"low prio t3 working here");
std::thread t4(lpt,"low prio t4 working here");
std::thread t5(lpt,"low prio t5 working here");
std::thread t6(hpt,"high prio t6 working here");
std::thread t7(lpt,"low prio t7 working here");
std::thread t8(hpt,"high prio t8 working here");
std::thread t9(lpt,"low prio t9 working here");
std::thread t10(lpt,"low prio t10 working here");
std::thread t11(lpt,"low prio t11 working here");
std::thread t12(hpt,"high prio t12 working here");
std::thread t13(lpt,"low prio t13 working here");
//std::cout << "All threads created" << std::endl;
t0.join();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
t8.join();
t9.join();
t10.join();
t11.join();
t12.join();
t13.join();
return 0;
}
What do you think? Is it ok? It's true that a semaphore could handle better this kind of thing, but mutexes are much more easy to manage to me.