Windows7内存管理 - 如何防止并发线程阻塞

时间:2014-01-22 17:50:21

标签: c++ multithreading memory-management nonblocking forward-list

我正在研究一个由两个并发线程组成的程序。一个(此处为“时钟”)正在定期执行一些计算(10 Hz),并且占用大量内存。另一个(这里是“hugeList”)使用更多的RAM但不像第一个那样具有时间关键性。所以我决定将其优先级降低到THREAD_PRIORITY_LOWEST。然而,当线程释放它使用的大部分内存时,关键的一个不能保持其时间。

我能够将问题压缩到这段代码中(确保优化已关闭!): 当Clock尝试保持10Hz时间时,hugeList-thread分配并释放越来越多的内存,而不是以任何类型的块组织。

#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)上,在“hugeList”方法的第四次迭代 - 时钟线程受到严重干扰(最多200ms)。如果没有dummyData-vector“询问”时钟线程中的某些内存,效果就会消失。

所以,

  1. 有没有办法增加Win7中Clock-Thread的内存分配优先级?
  2. 或者我是否必须将这两个操作拆分为两个上下文(进程)?
  3. 请注意,我的原始代码使用了一些通过共享变量进行的通信,如果我选择第二个选项,则需要使用某种IPC。

    请注意,当相当于“hugeList”-method清除boost :: unordered_map并多次输入ntdll.dll!RtIInitializeCriticalSection时,我的原始代码会被卡住大约1秒。 (observed by systinernals process explorer)

    请注意,观察到的效果不是由于交换,我使用的是1.4GB的16GB(64位win7)。

    修改

    只是想让你知道到目前为止我还没能解决我的问题。将代码的两个部分拆分到两个进程似乎不是一个选项,因为我的时间相当有限,到目前为止我从未使用过程。我恐怕无法及时找到正在运行的版本。

    但是,我设法通过减少非关键线程所做的内存释放次数来减少影响。这是通过使用快速池内存分配器(如boost库中提供的内存分配器)实现的。 似乎没有可能在某种不需要同步的threadprivate堆上显式创建某些对象(例如我的示例中的巨大转发列表)。

    进一步阅读:

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

    Do threads have a distinct heap?

    Memory Allocation/Deallocation Bottleneck?

    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

1 个答案:

答案 0 :(得分:0)

用std :: list替换std :: forward_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;

它不会重新创建。 似乎线程调度程序因为要求大量的小内存块而受到惩罚。