Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I have a boost lock-free queue of lambdas?

I'm trying to implement a messaging system that will work across multiple threads. boost::lockfree::queue seemed like a good direction to go in, unfortunately I'm having trouble creating a queue of either std::function or boost::function types as apparently they don't have trivial assignment and destructor's which is a requirement of boost::lockfree::queue.

My following code:

#include <cassert>
//#include <functional>
#include <iostream>

#include <boost/function.hpp>
#include <boost/lockfree/queue.hpp>

int main()
{
  boost::lockfree::queue<boost::function<void(int)>> queue;
  assert(queue.is_lock_free());

  for(int j = 0; j < 50; ++j) {
    queue.push([] (int i) { std::cout << i << std::endl; });
  }

  int i = 0;
  boost::function<void(int)> functor;
  while (queue.pop(functor)) {
    functor(i++);
  }
}

Produces the following output:

In file included from /usr/include/boost/integer.hpp:23:0,
                 from /usr/include/boost/function/function_base.hpp:21,
                 from /usr/include/boost/function/detail/prologue.hpp:17,
                 from /usr/include/boost/function.hpp:24,
                 from lockfree.cpp:5:
/usr/include/boost/lockfree/queue.hpp: In instantiation of ‘class boost::lockfree::queue<boost::function<void(int)> >’:
lockfree.cpp:10:54:   required from here
/usr/include/boost/lockfree/queue.hpp:81:5: error: static assertion failed (boost::has_trivial_destructor<T>::value)
     BOOST_STATIC_ASSERT((boost::has_trivial_destructor<T>::value));
     ^
/usr/include/boost/lockfree/queue.hpp:85:5: error: static assertion failed (boost::has_trivial_assign<T>::value)
     BOOST_STATIC_ASSERT((boost::has_trivial_assign<T>::value));

Is there any way to make this work?

like image 837
Sam Kellett Avatar asked Jan 28 '14 12:01

Sam Kellett


People also ask

Are lock free queues faster?

Lock-Free queues provides us better performance for concurrent queue which is non-blocking and linearizable. Although it introduces ABA problem, we have some workaround solutions for it. In general, if if don't want to lock your queue in concurrent programming, try lock-free queue algorithm.

What is SPSC queue?

The spsc_queue class provides a single-writer/single-reader fifo queue, pushing and popping is wait-free. Policies: boost::lockfree::capacity<> , optional. If this template argument is passed to the options, the size of the ringbuffer is set at compile-time.


2 Answers

You could still use stateless lambdas with raw function pointers, if that's an option:

#include <cassert>
#include <functional>
#include <iostream>

#include <boost/function.hpp>
#include <boost/lockfree/queue.hpp>

int main() {
    //boost::lockfree::queue<boost::function<void(int)>> queue(50);
    boost::lockfree::queue<void (*)(int)> queue(50);
    assert(queue.is_lock_free());

    for (int j = 0; j < 50; ++j) {
        queue.push([](int i) { std::cout << i << std::endl; });
    }

    int i = 0;
    boost::function<void(int)> functor;
    while (queue.pop(functor)) {
        functor(i++);
    }
}

http://coliru.stacked-crooked.com/a/d57770e3be029760

like image 190
pepper_chico Avatar answered Sep 30 '22 13:09

pepper_chico


You can use pointers to emulate trivial types. (This works for all lambdas)

#include <cassert>
#include <functional>
#include <iostream>

#include <boost/function.hpp>
#include <boost/lockfree/queue.hpp>

int main()
{
  boost::lockfree::queue<boost::function<void(int)>*> queue(3);
  assert(queue.is_lock_free());

  for(int j = 0; j < 50; ++j) {
    auto function = [] (int i) { std::cout << i << std::endl; };
    queue.push(new boost::function<void(int)>(function));
  }

  int i = 0;
  boost::function<void(int)> * functor;
  while (queue.pop(functor)) {
    functor->operator()(i++);
    delete functor;
  }
}
like image 30
voodooattack Avatar answered Sep 30 '22 14:09

voodooattack