22 Ağustos 2017 Salı

interprocess deque Sınıfı

Giriş
Şu satırı dahil ederiz.
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/deque.hpp>
Bu sınıfta polymorphic yapıları saklamak mümkün değil. Açıklaması şöyle
Virtuality forbidden
The virtual table pointer and the virtual table are in the address space of the process that constructs the object, so if we place a class with a virtual function or virtual base class, the virtual pointer placed in shared memory will be invalid for other processes and they will crash.
This problem is very difficult to solve, since each process needs a different virtual table pointer and the object that contains that pointer is shared across many processes. Even if we map the mapped region in the same address in every process, the virtual table can be in a different address in every process. To enable virtual functions for objects shared between processes, deep compiler changes are needed and virtual functions would suffer a performance hit. That's why Boost.Interprocess does not have any plan to support virtual function and virtual inheritance in mapped regions shared between processes.
POD
deque sınıfı POD değildir. İçindeki veriye push() pop() metodları ile erişilir. Şu kullanım yanlış.
memcpy(Mydeque_new, &Mydeque, Mydeque->size()*sizeof(Foo));
Mutex
deque sınıfını farklı uygulamalar aynı anda yazıp okuyorsa mutlaka bip::interprocess_mutex ile kullanmak gerekir.

Constructor - Allocator
Bu sınıf normalde managed_shared_memory içinde yaratılır. Böylece producer ve consumer sınıfları aynı kuyruğa erişebilir.

Örnek
Producer tarafında managed_shared_memory nesnesine find_or_construct(), construct() çağrısı yaparız.

Consumer tarafında ise managed_shared_memory nesnesine find() çağrısı yaparız.

Şöyle yaparız.
typedef bip::allocator<Foo, bip::managed_shared_memory::segment_manager> ShmemAllocator;
typedef bip::deque<Foo, ShmemAllocator> MyDeque;

bip::managed_shared_memory segment(bip::open_or_create, "MySharedMemory",50000000); 
const ShmemAllocator salloc (segment.get_segment_manager());
MyDeque *pDeque =
segment.find_or_construct<MyDeque>("myd")(alloc_inst);//first ctor parameter
Örnek
Template olarak kullanmak istersek şöyle yaparız.
template <class T>
class IConcurrentIPCQueue
{
public:
    virtual void push_back(T const & data) = 0;
    virtual bool pop_front(T & data) = 0;
virtual unsigned int size() = 0;
};

template <class T>
class ConcurrentIPCQueue :public IConcurrentIPCQueue<T>
{
public:
  // allocator for allocating memory from the shared memory
  typedef bip::allocator<T, bip::managed_shared_memory::segment_manager> ShmemAlloc;
  typedef bip::interprocess_mutex IPC_Mutex;
  typedef bip::interprocess_condition IPC_Cond;
  typedef boost::lock_guard<IPC_Mutex> LockGuard;

  ConcurrentIPCQueue(ShmemAlloc salloc) : q(salloc) { }

  ...
private:
  boost_ipc::deque<T, ShmemAlloc> q;
  IPC_Mutex mMutex_;
  IPC_Cond mWait_;
};
Bu sınıfı bir typedef haline getiririz.
typedef ConcurrentIPCQueue<char> myqueue;
producer tarafında şöyle yaparız.
bip::shared_memory_object::remove(SHMEMNAME);

bip::managed_shared_memory mysegment(bip::create_only, SHMEMNAME, 131072);

myqueue::ShmemAlloc alloc(mysegment.get_segment_manager());
myqueue*myQueue = mysegment.construct<myqueue>(SHQUEUENAME)(alloc);
consumer tarafında şöyle yaparız.
bip::managed_shared_memory openedSegment(bip::open_only, SHMEMNAME);
myqueue*openedQueue = openedSegment.find<myqueue>(SHQUEUENAME).first;
front metodu
Şöyle yaparız.
T data = q.front(); // return reference to first element
pop_front metodu
Şöyle yaparız.
q.pop_front(); // remove the first element
push_back metodu
Şöyle yaparız.
char mychar='A';
q.push_back (mychar);
size metodu
Şöyle yaparız.
return q.size();
Producer Consumer Kullanımı
Elimizde typedefler olsun.
typedef bip::interprocess_mutex IPC_Mutex;
typedef bip::interprocess_condition IPC_Cond;
typedef boost::lock_guard<IPC_Mutex> LockGuard;
Elimizde değişkenler olsun.
IPC_Mutex mutex;
IPC_Cond cond;
Kuyruğa bir şey eklerken şöyle yaparız.
void push_back(T const & data)
{
  {
    LockGuard lock(mutex);
    q.push_back(data);
  }
  cond.notify_one();
}
Kuyruktan çekerken şöyle yaparız.
bool pop_front(T & data)
{
  LockGuard lock(mutex);

  if (q.empty())
    return false;

  data = q.front(); // return reference to first element
  q.pop_front(); // remove the first element

  return true;
}

Hiç yorum yok:

Yorum Gönder