2016-07-27 13 views
0

Unten ist eine alte Übung für eine Klasse, die nicht mehr an meiner Universität unterrichtet wird (Parallel Processing). Das Ziel besteht darin, eine Speicherbank zu erstellen und zu verwenden, um die Lock-Free Sorted Vector-Implementierung zu beschleunigen. Ich habe die Memory Bank selbst implementiert und das Ziel ist es, genug Speicher zur Verfügung zu stellen, damit ich nicht neue oder löschen im LFSV verwenden muss. Ich glaube, ich brauche eine Get() - Funktion, die die Adresse des Speichers zurückgibt (nicht sicher, wie der unbenutzte Speicher verfolgt wird), und Store sollte den Speicher freigeben (irgendwie als unbenutzt markieren).Wie erstelle ich einen richtigen Speicherpool für einen Multithread-Vektor (LFSV)?

Innerhalb LFSV (was vor meiner Intervention völlig in Ordnung war), erklärt die Übung, dass ich die neue ersetzen und löschen mit neuen Ersatz und Speicher (Speicher wollen wir befreit). Wie gehe ich vor beim Erstellen der Get (wenn dies falsch ist) oder der Store-Funktion, um wie eine richtige Speicherbank zu funktionieren? Ich werde auch irgendwelche Referenz- oder Speicherbankbeispiele online nehmen, von denen Sie vielleicht wissen, dass ich Probleme habe, gute Ressourcen in Bezug auf Speicherbänke und Multithreading zu finden.

Es gibt keine Fehler in diesem Programm, aber es kehrt als "FAIL" zurück, da ich die Speicherbank nicht richtig verwaltet habe.

#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

Diese werden häufiger Speicherpools genannt. – immibis

Antwort

0

reinterpret_cast ist wirklich ein "Ich weiß, was ich tue, vertrau mir" Cast. Der Compiler wird Ihnen - wenn möglich - glauben.

In diesem Fall ist es jedoch völlig falsch. new char[] tut nicht geben Sie eine vector<int>* zurück.

+0

Was wäre die korrekte Syntax für die "reinterpret_cast"? –

+0

@AmrotheStudent: Die verwendete Syntax stimmt mit der Grammatik überein. Die Logik dahinter ist jedoch nur fehlerhaft. Ich kann keine einfache Lösung sehen. Was sollen diese Slots enthalten? Ich sehe 4 Methoden und 4 verschiedene Typen ('new char [], Vektor , Vektor , void *'). – MSalters

+0

Ich glaube, die Get() - Funktion wird verwendet, um der neuen Platzierung in der LFSV-Klasse einen Speicherort für die Verwendung des Speichers zu geben. Und ich glaube, dass eine neue Platzierung eine Lücke erfordert *. Der LFSV ist ein Vektor , der von der Speicherbank verwaltet wird. Die Zeile: slots [i] = reinterpret_cast *> (neues Zeichen [sizeof (std :: vector )]); war in der Memory Bank Skelett, dass die Übung für den Anfang hatte, so bin ich mir nicht sicher, ob das richtig oder falsch ist, da ich nicht mit reinterpret_cast vertraut bin. –