Ниже приведено упражнение для класса, который больше не преподаётся в моем университете (параллельная обработка). Цель состоит в том, чтобы создать и использовать банк памяти для ускорения реализации 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