다음은 제 대학에서 더 이상 가르치지 않는 수업에 대한 오래된 연습입니다 (병렬 처리). 목표는 메모리 뱅크를 생성하고 사용하여 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;
}
}
더 흔히 메모리 풀이라고합니다. – immibis