Reputation: 5465
I have a std::deque<std::reference_wrapper<MyType>> mydeque
. I need a function that returns the front value (as a plain reference) and pops it from the queue. As std::deque
are not thread safe, access should be protected (I'm using OpenMP).
I came up with the ugly code below. It looks very bad having such advanced structures and then falling back to a raw pointer.
MyType & retrieve() {
MyType* b;
#pragma omp critical(access_mydeque)
{
b = &(mydeque.front().get());
mydeque.pop_front();
}
return *b;
}
The problem is that I cannot return within the critical section, but I also cannot declare a reference(_wrapper) before the critical section (because it must be assigned to something)... Is there a way to solve this?
Upvotes: 2
Views: 265
Reputation: 2869
You could simply use TBB's parallel data structures https://software.intel.com/en-us/node/506076 (though since there is no concurrent_deque they may not be perfect for you :-( ).
They do not require that you also use TBB to describe the parallelism aspects of your code, so can be mixed into an OpenMP code. (Of course, since you're using C++ you might find TBB's approach to scalable, composable, parallelism more friendly than OpenMP's, but that's a separable decision).
Upvotes: 1
Reputation: 8032
Any solution I can think of involves using an omp_lock_t
instead of the critical
construct and a RAII class managing the omp_lock_t
ownership:
class LockGuard {
public:
explicit LockGuard(omp_lock_t& lock) : m_lock(lock){
omp_set_lock(&m_lock);
}
~LockGuard() {
omp_unset_lock(&m_lock);
}
private:
omp_lock_t& m_lock;
};
Then you can either modify the code you already have into something like:
MyType & retrieve() {
LockGuard guard(mydeque_lock);
auto b = mydeque.front();
mydeque.pop_front();
return b;
}
or better, write your own thread-safe container that aggregates the lock and the std::deque
:
template<class T>
class MtLifo {
public:
MtLifo() {
omp_init_lock(&m_lock);
}
typename std::deque<T>::reference front_and_pop() {
LockGuard guard(m_lock);
auto b = m_stack.front();
m_stack.pop_front();
return b;
}
void push_front(const T& value) {
LockGuard guard(m_lock);
m_stack.push_front(value);
}
~MtLifo() {
omp_destroy_lock(&m_lock);
}
private:
std::deque<T> m_stack;
omp_lock_t m_lock;
}
Upvotes: 2