2016-07-27 5 views
0

Ниже приведено упражнение для класса, который больше не преподаётся в моем университете (параллельная обработка). Цель состоит в том, чтобы создать и использовать банк памяти для ускорения реализации Lock-Free Sorted Vector. Я сам реализовал Банк памяти, и цель состоит в том, чтобы выделить достаточно памяти для использования, поэтому мне не нужно использовать новое или удалить в LFSV. Я считаю, что мне нужна функция Get(), которая возвращает адрес памяти (не уверен, как отслеживать неиспользуемую память), и Store должен освободить память (как-то отметить ее как неиспользованную).Как создать правильный пул памяти для многопоточного вектора (LFSV)?

Внутри LFSV (который работал отлично до моего вмешательства), упражнение объясняет, что я должен заменить новый и удалить новую замену и Store (память, которую мы хотим освободить). Как мне сделать создание Get (если это неверно) или функцию Store для работы как надлежащий банк памяти? Я также буду использовать любые примеры ссылок или банковских счетов в Интернете, о которых вы, возможно, знаете, потому что мне трудно найти хорошие ресурсы, связанные с банками памяти и многопоточными операциями.

У этой программы нет ошибок, но она возвращает себя как «FAIL», так как я неправильно управлял банком памяти.

#include <algorithm>//copy, random_shuffle 
#include <ctime> //std::time (NULL) to seed srand 
#include <iostream>  // std::cout 
#include <atomic>   // std::atomic 
#include <thread>   // std::thread 
#include <vector>   // std::vector 
#include <mutex>   // std::mutex 
#include <deque>   // std::deque 

class MemoryBank 
{ 
    std::deque< std::vector<int>* > slots; 
public: 
    MemoryBank() : slots(10000) 
    { 
     for (int i = 0; i<10000; ++i) 
     { 
      slots[i] = reinterpret_cast<std::vector<int>*>(new char[sizeof(std::vector<int>)]); 
     } 
    } 
    ~MemoryBank() 
    { 
     for (unsigned int i = 0; i < slots.size(); ++i) 
     { 
      delete slots[i]; 
     } 
     slots.clear(); 
    } 
    void * Get() 
    { 
     return &slots; 
    } 
    void Store(std::vector<int *> freeMemory) 
    { 
     return; 
    } 
}; 

class LFSV { 
    std::atomic< std::vector<int>* > pdata; 
    std::mutex wr_mutex; 
    MemoryBank mb; 

    public: 

    LFSV() : mb(), pdata(new (mb.Get()) std::vector<int>) {} 

    ~LFSV() 
    { 
     mb.~MemoryBank(); 
    } 

    void Insert(int const & v) { 
     std::vector<int> *pdata_new = nullptr, *pdata_old; 
     int attempt = 0; 
     do { 
      ++attempt; 
      delete pdata_new; 
      pdata_old = pdata; 
      pdata_new = new (mb.Get())std::vector<int>(*pdata_old); 

      std::vector<int>::iterator b = pdata_new->begin(); 
      std::vector<int>::iterator e = pdata_new->end(); 
      if (b==e || v>=pdata_new->back()) { pdata_new->push_back(v); } //first in empty or last element 
      else { 
       for (; b!=e; ++b) { 
        if (*b >= v) { 
         pdata_new->insert(b, v); 
         break; 
        } 
       } 
      } 
//   std::lock_guard<std::mutex> write_lock(wr_mutex); 
//   std::cout << "insert " << v << "(attempt " << attempt << ")" << std::endl; 
     } while (!(this->pdata).compare_exchange_weak(pdata_old, pdata_new )); 
     // LEAKing pdata_old since "delete pdata_old;" will cause errors 


//  std::lock_guard<std::mutex> write_lock(wr_mutex); 
//  std::vector<int> * pdata_current = pdata; 
//  std::vector<int>::iterator b = pdata_current->begin(); 
//  std::vector<int>::iterator e = pdata_current->end(); 
//  for (; b!=e; ++b) { 
//   std::cout << *b << ' '; 
//  } 
//  std::cout << "Size " << pdata_current->size() << " after inserting " << v << std::endl; 
    } 

    int const& operator[] (int pos) const { 
     return (*pdata)[ pos ]; 
    } 
}; 

LFSV lfsv; 

void insert_range(int b, int e) { 
    int * range = new int [e-b]; 
    for (int i=b; i<e; ++i) { 
     range[i-b] = i; 
    } 
    std::srand(static_cast<unsigned int>(std::time (NULL))); 
    std::random_shuffle(range, range+e-b); 
    for (int i=0; i<e-b; ++i) { 
     lfsv.Insert(range[i]); 
    } 
    delete [] range; 
} 

int reader(int pos, int how_many_times) { 
    int j = 0; 
    for (int i=1; i<how_many_times; ++i) { 
     j = lfsv[pos]; 
    } 
    return j; 
} 

std::atomic<bool> doread(true); 

void read_position_0() { 
    int c = 0; 
    while (doread.load()) { 
     std::this_thread::sleep_for(std::chrono::milliseconds(10)); 
     if (lfsv[0] != -1) { 
      std::cout << "not -1 on iteration " << c << "\n"; // see main - all element are non-negative, so index 0 should always be -1 
     } 
     ++c; 
    } 
} 

void test(int num_threads, int num_per_thread) 
{ 
    std::vector<std::thread> threads; 
    lfsv.Insert(-1); 
    std::thread reader = std::thread(read_position_0); 

    for (int i=0; i<num_threads; ++i) { 
     threads.push_back(std::thread(insert_range, i*num_per_thread, (i+1)*num_per_thread)); 
    } 
    for (auto& th : threads) th.join(); 

    doread.store(false); 
    reader.join(); 

    for (int i=0; i<num_threads*num_per_thread; ++i) { 
     //  std::cout << lfsv[i] << ' '; 
     if (lfsv[i] != i-1) { 
      std::cout << "Error\n"; 
      return; 
     } 
    } 
    std::cout << "All good\n"; 
} 

void test0() { test(1, 100); } 
void test1() { test(2, 100); } 
void test2() { test(8, 100); } 
void test3() { test(100, 100); } 

void (*pTests[])() = { 
    test0,test1,test2,test3//,test4,test5,test6,test7 
}; 


#include <cstdio> /* sscanf */ 
int main(int argc, char ** argv) { 
    if (argc==2) { //use test[ argv[1] ] 
     int test = 0; 
     std::sscanf(argv[1],"%i",&test); 
     try { 
      pTests[test](); 
     } catch(const char* msg) { 
      std::cerr << msg << std::endl; 
     } 
     return 0; 
    } 
} 
+0

Это чаще всего называемые пулами памяти. – immibis

ответ

0

reinterpret_cast действительно «Я знаю, что я делаю, поверьте мне» слепок. Компилятор, если возможно, поверит вам.

Однако в этом случае это совершенно неправильно. new char[]не возвращение vector<int>*.

+0

Каким будет правильный синтаксис для «reinterpret_cast?»? –

+0

@AmrotheStudent: Используется _syntax_ в соответствии с грамматикой. Однако логика этого лишь ошибочна. Я не вижу легкого решения. Что должны содержать эти слоты? Я вижу 4 метода и 4 разных типа ('новый char [], вектор , вектор , void *'). – MSalters

+0

Я считаю, что функция Get() используется, чтобы дать новому месту размещения в классе LFSV место для использования памяти. И я считаю, что новое размещение требует пустоты *. LFSV - это вектор , которым управляет Банк памяти. Линия: слоты [i] = reinterpret_cast *> (новый char [sizeof (std :: vector )]); был в скелете банка памяти, который было выполнено для начала, поэтому я не уверен, правильно это или нет, поскольку я не знаком с reinterpret_cast. –