Skip to content

Concurrent wrapper for "any" object. All calls to the public API of the object are executed asynchronously in FIFO order.

License

Notifications You must be signed in to change notification settings

KjellKod/concurrent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

76 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

concurrent<T> wrapper

Makes access to any object asynchronous. All asynchronous calls will be executed in the background and in FIFO order.

The concurrent<T> wrapper can be called in two ways.

1 As suggested by [Herb Sutter in C++ and Beyond 2012] (http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Herb-Sutter-Concurrency-and-Parallelism)

  • Many actions can be bundled together in one asynchronous operation
  • All calls are made through a lambda call that takes a reference to the wrapped object as input argument
  • See example from the unit tests:
class Greetings {
 std::string _msg;
 public:
  explicit Greetings(const std::string& msg) : _msg(msg){}
  std::string Hello(size_t number) { 
     return {_msg + " " + std::to_string(number)};
  }
  
  concurrent<Greetings> greeting{"Hello World"};
  // execute two Hello calls in one asynchronous operation. 
  std::future<std::string> response = greeting.lambda( 
      [](Greetings& g) { 
         std::string reply{g.Hello(123) + " " + g.Hello(456)}; 
         return reply;
       }
     ); // Hello World 123 Hello World 456
  EXPECT_EQ(response.get(), "Hello World 123 Hello World 456");
  
  

2 As used in the asynchronous, "crash-safe" logger, G3Log , using a function-pointer syntax.

  • This is a safer approch, it's protected from unintentianal abuse. Compare this to the lambda approach where the lambda capture is powerful but can cause unintended problems if the lambda capturing ia used irresponsibly.
  • Only one action can be done per each asynchronous request.
  • See example from unit tests:
   concurrent<Greetings> greeting2{"Hello World"};
   // execute ONE Hello in one asynchronous operation. 
   std::future<std::string> response2 = greeting.call(&Greetings::Hello, 789); 
   EXPECT_EQ(response2.get(), "Hello World 789");

3 Both can be used for derived objects of abstract types

  • See example from unit tests:
   struct Animal {
      virtual std::string sound() = 0;
   };
  
   struct Dog : public Animal {
      std::string sound() override {
         return  {"Wof Wof"};
      }
   };

   struct Cat : public Animal {
      std::string sound() override {
         return {"Miauu Miauu"};
      }
   };
   
   
 
  // Internally the concurrent<T> wrapper keeps the object in a std::unique_ptr<T>  
  concurrent<Animal> animal1{std::unique_ptr<Animal>(new Dog)};  
  concurrent<Animal> animal2{std::unique_ptr<Animal>(new Cat)};

  // lambda syntax
  auto make_sound = [](Animal& animal) { return animal.sound();  };
  EXPECT_EQ("Wof Wof", animal1.lambda(make_sound).get());

  // function-call syntax
  EXPECT_EQ("Miauu Miauu", animal2.call(&Animal::sound).get());

About

Concurrent wrapper for "any" object. All calls to the public API of the object are executed asynchronously in FIFO order.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published