Я включил исходный код, который вы можете скомпилировать и увидеть проблему для себя. скомпилировать с помощью g ++ -lpthread list-memchk.cpp -o list-memchk
Выполните это, например, ./list-memchk 43000000 30000000 10
я включил три файла, первый,
Список-memchk.cpp
#include <cstdlib>
#include <iostream>
#include <pthread.h>using namespace std;struct node
{
public :
unsigned int part1; // 4 bytes
unsigned int part2; // 4 bytes
node *next; //pointer, 8 bytes on 64 bit system
unsigned int read_part1();
};struct LinkedList
{
public:
LinkedList();
void insert(unsigned int data[], unsigned int data1);
bool isEmpty() const;
node* head;
};
unsigned int node::read_part1() {
return part1;
}
LinkedList::LinkedList():
head(NULL)
{
}
bool LinkedList::isEmpty() const
{
return (head == NULL);
}
void LinkedList::insert(unsigned int data[], unsigned int data1)
{node* oldHead = head;
node* newHead = new node();
newHead->part1 = data[0];
newHead->part2 = data1;
newHead->next = oldHead;
head = newHead;
}
unsigned int allocations = 300000000;
unsigned int index_size = 430000000;//index of lists, 430m,.
pthread_mutex_t mutex;
//will be creatad on heap
LinkedList *list = NULL;unsigned long node_count() {
unsigned long numNodes = 0;for (int i=0; i<index_size; i++)
{node* current = list[i].head;
// if root is null, the number of nodes is 0
if(current != NULL) {
// if root is not null, we have at least one node
numNodes++;
// count all nodes
while(current->next != NULL) {
numNodes++;
current = current->next;
}
}
}
return numNodes;
}#include "alloc_threads.cpp"void start_threads(int thread_count) {
alloc_threads alloc_thr[thread_count];//thread objects
pthread_t threads[thread_count];
pthread_mutex_init(&mutex, NULL);
for (int i=0; i<thread_count; i++)
{
alloc_threads *rr;
rr = new alloc_threads(list, mutex, allocations);
alloc_thr[i] = *rr;
pthread_create(&threads[i], NULL, &alloc_threads::allocation_helper,&alloc_thr[i]);
delete rr;
}
for (int i=0; i<thread_count; i++)
pthread_join( threads[i], NULL);}int main(int argc, char *argv[])
{
if ( argc < 4 )
{
std::cout << "Missing paramaters. " << endl;
std::cout << "Please run me like this : <list-memchk> <index_size> <allocations_per_thread> <thread_count>" << endl;
return 1;
}index_size = strtoul(argv[1], 0, 10);
allocations = strtoul(argv[2], 0, 10);
unsigned int thr_cnt = strtoul(argv[3], 0, 10);
LinkedList list_instance;
cout << "1 LinkedList instance takes [" << sizeof(list_instance) << "] bytes in memory!"<< endl;
node node_instance;
cout << "1 node instance takes [" << sizeof(node_instance) <<"] bytes in memory !"<< endl;list = new (nothrow) LinkedList[index_size];
if (!list)
{
cout << "Error allocating memory" << endl;
return 1;
}unsigned int some_data[] = {00, 01};
unsigned int index;
cout << "Allocating ..." << endl;
start_threads(thr_cnt);unsigned long sk = ((allocations * sizeof(node_instance) + index_size*sizeof(list_instance))) / (1024*1024*1024);
cout << "This process *should* consume around " << sk <<" GBytes of memory, but does it ?"<< endl;
cout << "Allocating done, *check the process size* ..." << endl;cout << "Lets count `nodes` to see how many do we have; counting, please wait ..." << endl;
cout << "We have reached [" << node_count() << "] nodes, expected [" << allocations * thr_cnt << "] nodes. You may press any number key to exit." << endl;
string s;
getline(std::cin, s);return 0;
}
затем,
alloc_threads.cpp
#include "alloc_threads.h"using namespace std;
alloc_threads::alloc_threads()
{
}
void *alloc_threads::allocation_helper(void *context)
{
return ((alloc_threads *)context)->allocation();
}
alloc_threads::alloc_threads(LinkedList* x_list, pthread_mutex_t x_mutex, unsigned int x_allocations){
list = x_list;
mutex = x_mutex;
allocations = x_allocations;
}
void * alloc_threads::allocation(void)
{
cout << "Thread started" << endl;
unsigned int some_data[] = {00, 01};
unsigned int index;
unsigned short inde;
LinkedList *list_instance2 = NULL;
for (int i=0; i<allocations; i++)
{
pthread_mutex_lock(&mutex);index = rand();
inde = (unsigned short)index;
list_instance2 = &list[inde];
list_instance2->insert(some_data, some_data[1]);
pthread_mutex_unlock(&mutex);
}
cout << "Thread finished" << endl;
return 0;
}
alloc_threads::~alloc_threads()
{
}
и наконец,
alloc_threads.h
class alloc_threads{
public:
void *allocation(void);
static void *allocation_helper(void *context);
alloc_threads();
alloc_threads(LinkedList *x_list, pthread_mutex_t x_mutex, unsigned int x_allocations);
~alloc_threads();
private:
pthread_mutex_t mutex;
LinkedList* list;
unsigned int allocations;
};
Сам код вообще не комментируется, но, надеюсь, его не так сложно понять. Что я сделал, так это выделение памяти стандартным распределителем в нескольких параллельных потоках, скажем, 10, например. после того, как распределение сделано во всех потоках, я получаю доступ к каждому узлу и увеличиваю numNodes
после успешного доступа. что я обычно получаю, это numNodes
значение будет на несколько / несколько сотен или несколько тысяч меньше ожидаемого. что случилось ? и я сделал это с двумя разными распределителями, оба они имеют одинаковое поведение.
Кажется, я неправильно использую мьютекс — он не останавливает одновременную запись потоков в одну и ту же память.
solution
я нашел, это: определение переменной мьютекса в list-memchk.cpp и избегать передачи его в потоки, но используя его as is
,
list-memchk.cpp:
заменить определение мьютекса этим,
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER ;
Удалить
pthread_mutex_init(&mutex, NULL);
alloc_threads.h:
удалить мьютекс из этого файла;
alloc_threads.cpp:
Удалить mutex = x_mutex;
Это оно. Нет больше отсутствующих узлов. Тем не менее, скорость выделения жалкая. Похоже, потоки ждут друг друга, чтобы разблокировать мьютекс; Ядра процессора работают на холостом ходу, а распределение занимает огромное количество времени.
Других решений пока нет …