POSIX 线程 - 使用条件变量 MEMORY LEAK 同步 DETACHED 线程
POSIX Threads - synchronize DETACHED threads using conditional variable MEMORY LEAK
您好,我正在尝试使用条件变量同步分离的线程,但我发现了一个有时会导致内存泄漏的错误(取决于调度程序心情)。我认为代码是不言自明的。如果有任何建议,我将不胜感激。
#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,并在实际分离的线程退出之前终止。每个 运行 线程,即使是分离的线程,也会消耗和分配一点内部内存,直到线程实际终止时才会释放这些内存。这是您看到的泄漏,来自在主执行线程停止之前未终止的执行线程。
这不是您需要担心的泄漏。这很烦人,并且使调试变得困难,真的。
过去,我在我前段时间写的一个框架class库中采用了一种方法。我根本没有使用分离线程,但所有线程都是可连接线程。该框架启动了一个单独的后台线程,其唯一的工作是 join()
终止的线程。然后,框架启动的每个线程都会在每个线程终止之前为单例后台线程排队自己的线程 ID。
净效果等同于分离线程。我可以启动每个线程而不用担心加入它。这将是后台线程的工作。该框架将向后台线程发出信号以终止自身,并在退出之前加入它。因此,如果一切顺利,将不会报告任何可归因于线程支持的内存泄漏。
您好,我正在尝试使用条件变量同步分离的线程,但我发现了一个有时会导致内存泄漏的错误(取决于调度程序心情)。我认为代码是不言自明的。如果有任何建议,我将不胜感激。
#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,并在实际分离的线程退出之前终止。每个 运行 线程,即使是分离的线程,也会消耗和分配一点内部内存,直到线程实际终止时才会释放这些内存。这是您看到的泄漏,来自在主执行线程停止之前未终止的执行线程。
这不是您需要担心的泄漏。这很烦人,并且使调试变得困难,真的。
过去,我在我前段时间写的一个框架class库中采用了一种方法。我根本没有使用分离线程,但所有线程都是可连接线程。该框架启动了一个单独的后台线程,其唯一的工作是 join()
终止的线程。然后,框架启动的每个线程都会在每个线程终止之前为单例后台线程排队自己的线程 ID。
净效果等同于分离线程。我可以启动每个线程而不用担心加入它。这将是后台线程的工作。该框架将向后台线程发出信号以终止自身,并在退出之前加入它。因此,如果一切顺利,将不会报告任何可归因于线程支持的内存泄漏。