POSIX 线程 - 使用条件变量 MEMORY LEAK 同步分离的线程

POSIX Threads - synchronize DETACHED threads using conditional variable MEMORY LEAK

本文关键字:线程 LEAK 同步 MEMORY 分离 条件 POSIX 变量      更新时间:2023-10-16

您好,我正在尝试使用条件变量同步分离的线程,但我发现了一个有时会导致内存泄漏的错误(取决于调度程序的心情)。我认为代码是不言自明的。我将不胜感激任何建议。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
using namespace std;
struct TThrArg
{
    pthread_t m_ID;
    bool      m_IsRunning;
};
TThrArg         g_Threads[64];
int             g_Counter;
pthread_mutex_t g_Mtx;
pthread_cond_t  g_Cond;
void * thrFunc ( void * arg )
{
    TThrArg * data = (TThrArg *) arg;
    // do some stuff
    // -----------------------------------
    // for ( int i = 0; i < 5000; ++i )
    //  for ( int j = 0; j < 5000; ++j )
    //      int x = 0;
    // printf("Thread: %lu running...n", data->m_ID);
    // -----------------------------------
    pthread_mutex_lock(&g_Mtx);
    memset(data, 0, sizeof(TThrArg));
    --g_Counter;
    pthread_cond_signal(&g_Cond);
    pthread_mutex_unlock(&g_Mtx);
    sleep(1); // --> this spot causes that main may end before return NULL so resources will not be freed 
    return NULL;
}
void createThread ( void )
{
    pthread_mutex_lock(&g_Mtx);
    for ( int i = 0; i < 64; ++i )
    {
        if ( g_Threads[i].m_IsRunning == 0 )
        {
            g_Threads[i].m_IsRunning = 1;
            ++g_Counter;
            pthread_attr_t attr;
            pthread_attr_init(&attr);
            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
            pthread_create(&g_Threads[i].m_ID, &attr, thrFunc, &g_Threads[i]);
            pthread_attr_destroy(&attr);
            break;
        }
    }
    pthread_mutex_unlock(&g_Mtx);
}
int main ( int argc, char * argv[] )
{
    pthread_mutex_init(&g_Mtx, NULL);
    pthread_cond_init(&g_Cond, NULL);
    g_Counter = 0;
    for ( int i = 0; i < 64; ++i )
        createThread();
    pthread_mutex_lock(&g_Mtx);
    while ( g_Counter != 0 )
    {
        pthread_cond_wait(&g_Cond, &g_Mtx);
    }
    pthread_mutex_unlock(&g_Mtx);
    pthread_mutex_destroy(&g_Mtx);
    pthread_cond_destroy(&g_Cond);
    return 0;
}

您看到的泄漏是因为终止线程会减少受互斥锁保护的线程计数器,并在线程实际终止之前暂停一秒钟。

主执行线程将立即看到线程计数器达到 0,并在实际分离的线程退出之前终止。每个正在运行的线程(甚至是分离的线程)都会消耗和分配一点内部存储器,直到线程实际终止才会释放。这是您看到的泄漏,来自在主执行线程停止之前未终止的执行线程。

这不是您需要担心的泄漏类型。这很烦人,并且使调试变得困难,这是真的。

过去,我在前段时间编写的框架类库中采用了一种方法。我根本没有使用分离的线程,但所有线程都是可连接的线程。该框架启动了一个单例后台线程,其唯一工作是join()终止的线程。然后,框架启动的每个线程将在每个线程终止之前,为单一实例后台线程排队自己的线程 ID。

净效应相当于分离的线程。我可以启动每个线程,而不必担心加入它。这将是后台线程的工作。框架将向后台线程发出信号,使其在退出之前自行终止并加入它。因此,如果一切顺利,将不会有任何报告的内存泄漏可以归因于线程支持。