Управление памятью в Windows7 — как предотвратить одновременную блокировку потоков

Я работаю над программой, состоящей из двух параллельных потоков. Один (здесь «Clock») выполняет некоторые вычисления на регулярной основе (10 Гц) и довольно интенсивно использует память. Другой (здесь «огромный список») использует даже больше оперативной памяти, но не так критичен по времени, как первый. Поэтому я решил уменьшить его приоритет до THREAD_PRIORITY_LOWEST. Тем не менее, когда поток освобождает большую часть памяти, которую использовал, критический не удается сохранить время.

Мне удалось сжать проблему до этого фрагмента кода (убедитесь, что оптимизации отключены!):
в то время как Clock пытается поддерживать тактовую частоту 10 Гц, нить огромныйList-потока распределяет и освобождает все больше и больше памяти, не организованной в каких-либо порциях.

#include "stdafx.h"#include <stdio.h>
#include <forward_list>
#include <time.h>
#include <windows.h>
#include <vector>

void wait_ms(double _ms)
{
clock_t endwait;
endwait = clock () + _ms * CLOCKS_PER_SEC/1000;
while (clock () < endwait) {}   // active wait
}
void hugeList(void)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
unsigned int loglimit = 3;
unsigned int limit = 1000;
while(true)
{
for(signed int cnt=loglimit; cnt>0; cnt--)
{
printf(" Countdown %d...\n", cnt);
wait_ms(1000.0);
}
printf(" Filling list...\n");
std::forward_list<double> list;
for(unsigned int cnt=0; cnt<limit; cnt++)
list.push_front(42.0);
loglimit++;
limit *= 10;
printf(" Clearing list...\n");
while(!list.empty())
list.pop_front();
}
}
void Clock()
{
clock_t start = clock()-CLOCKS_PER_SEC*100/1000;
while(true)
{
std::vector<double> dummyData(100000, 42.0);    // just get some memory
printf("delta: %d ms\n", (clock()-start)*1000/CLOCKS_PER_SEC);
start = clock();
wait_ms(100.0);
}
}

int main()
{
DWORD dwThreadId;

if (CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&Clock, (LPVOID) NULL, 0, &dwThreadId) == NULL)
printf("Thread could not be created");
if (CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&hugeList, (LPVOID) NULL, 0, &dwThreadId) == NULL)
printf("Thread could not be created");

while(true) {;}
return 0;
}

Прежде всего я заметил, что выделение памяти для связанного списка происходит намного быстрее, чем его освобождение.
На моей машине (Windows7) примерно на 4-й итерации метода «огромный список» Clock-Thread значительно возмущается (до 200 мс). Эффект исчезает без dummyData-вектора, «запрашивающего» память в Clock-Thread.

Так,

  1. Есть ли способ увеличить приоритет выделения памяти для Clock-Thread в Win7?
  2. Или мне нужно разделить обе операции на два контекста (процесса)?

Обратите внимание, что мой исходный код использует некоторую связь через общие переменные, которые потребуются для какого-то IPC, если я выберу второй вариант.

Обратите внимание, что мой исходный код застревает примерно на 1 секунду, когда эквивалент метода «огромный список» очищает boost :: unordered_map и вводит ntdll.dll! RtIInitializeCriticalSection много раз.
(наблюдается исследователем систинернала)

Обратите внимание, что наблюдаемые эффекты не из-за подкачки, я использую 1,4 ГБ из 16 ГБ (64-битная win7).

редактировать:

Я просто хотел сообщить вам, что до сих пор я не смог решить мою проблему. Разделение обеих частей кода на два процесса не представляется возможным, так как мое время довольно ограничено, и я до сих пор никогда не работал с процессами. Боюсь, я не смогу вовремя добраться до работающей версии.

Однако мне удалось уменьшить эффекты, уменьшив количество выделений памяти некритическим потоком. Это было достигнуто с помощью быстрого распределителя памяти пула (как тот, который предоставлен в библиотеке повышения).
Кажется, не существует возможности явного создания определенных объектов (например, огромного списка пересылки в моем примере) в какой-то куче потока, которая не требует синхронизации.

Для дальнейшего чтения:

http://bmagic.sourceforge.net/memalloc.html

У потоков есть отличная куча?

Узкое место в распределении / выделении памяти?

http://software.intel.com/en-us/articles/avoiding-heap-contention-among-threads

http://www.boost.org/doc/libs/1_55_0/libs/pool/doc/html/boost_pool/pool/introduction.html

4

Решение

Заменив std :: forward_list на std :: list, я запускал ваш код на компьютере corei7 4GB, пока не израсходовал 2GB. Нарушений нет вообще. (В отладочной сборке)

P.S

Да. Сборка релиза воссоздает проблему. Я заменил передний список на массив

double* p = new double[limit];
for(unsigned int cnt=0; cnt<limit; cnt++)
p[cnt] = 42.0;

а также

for(unsigned int cnt=0; cnt<limit; cnt++)
p[cnt] = -1;
delete [] p;

Это не воссоздает тогда.
Кажется, что планировщик потоков требует много маленьких кусочков памяти.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]