2016-07-27 4 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 가지 타입이 있습니다 ('new char [], 벡터 , 벡터 , void *'). – MSalters

+0

Get() 함수는 LFSV 클래스의 새 배치에 메모리를 사용할 위치를 지정하는 데 사용됩니다. 그리고 새로운 게재 위치에는 무효가 필요하다고 생각합니다 *. LFSV는 메모리 뱅크가 관리하는 벡터 입니다. 줄 번호 : 슬롯 [i] = reinterpret_cast *> (새 char [sizeof (std :: vector )]); 은 연습을 시작하기 위해 메모리 뱅크 골격에 있었기 때문에 reinterpret_cast에 익숙하지 않아서 그것이 옳은 것인지 잘못되었는지 확실하지 않습니다. –