您好我正在尝试使用条件变量同步分离的线程,但我发现了一个有时会导致内存泄漏的错误(取决于调度程序的情绪)。我认为代码是自我解释的。我很感激任何建议。
#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 :(得分:0)
您看到的泄漏是因为终止线程减少受互斥锁保护的线程计数器,并在线程实际终止之前暂停一秒。
主执行线程将立即看到线程计数器达到0,并在实际分离线程退出之前终止。每个正在运行的线程,甚至是一个分离的线程,都会消耗并分配一些内部内存,直到线程实际终止才会释放内存。这是你看到的泄漏,来自在主执行线程停止之前没有终止的执行线程。
这不是您需要担心的那种泄漏。这是相当烦人的,并使调试变得困难,真实。
过去,我在一段时间前写过的框架类库中采用了一种方法。我根本没有使用分离线程,但所有线程都是可连接线程。该框架启动了一个单独的后台线程,其唯一的工作是join()
终止的线程。然后,框架启动的每个线程将在每个线程终止之前为单例后台线程排队自己的线程id。
净效果相当于分离的线程。我可以开始每个线程而不用担心加入它。这将是后台线程的工作。在退出之前,框架将通知后台线程终止自身并加入它。因此,如果一切顺利,将不会有任何报告的内存泄漏可以计入线程支持。