Joinable threads VS Detached threads
線程有兩種運行模式:
- Joinable Mode
- Detached Mode
Joinable Thread & pthread_join()
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
void * threadFunc(void * arg)
{
std::cout << "Thread Function :: Start" << std::endl;
// Sleep for 2 seconds
sleep(2);
std::cout << "Thread Function :: End" << std::endl;
// Return value from thread
return new int(6);
}
int main()
{
// Thread id
pthread_t threadId;
// Create a thread that will funtion threadFunc()
int err = pthread_create(&threadId, NULL, &threadFunc, NULL);
// Check if thread is created sucessfuly
if (err)
{
std::cout << "Thread creation failed : " << strerror(err);
return err;
}
else
std::cout << "Thread Created with ID : " << threadId << std::endl;
// Do some stuff
void * ptr = NULL;
std::cout << "Waiting for thread to exit" << std::endl;
// Wait for thread to exit
err = pthread_join(threadId, &ptr);
if (err)
{
std::cout << "Failed to join Thread : " << strerror(err) << std::endl;
return err;
}
if (ptr)
std::cout << " value returned by thread : " << *(int *) ptr
<< std::endl;
delete (int *) ptr;
return 0;
}
Detached Thread & pthread_detach()
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
void * threadFunc(void * arg)
{
std::cout << "Thread Function :: Start" << std::endl;
std::cout << "Thread Function :: End" << std::endl;
// Return value from thread
return NULL;
}
int main()
{
// Thread id
pthread_t threadId;
// Create a thread that will funtion threadFunc()
int err = pthread_create(&threadId, NULL, &threadFunc, NULL);
// Check if thread is created sucessfuly
if (err)
{
std::cout << "Thread creation failed : " << strerror(err);
return err;
}
else
std::cout << "Thread Created with ID : " << threadId << std::endl;
// Do some stuff
err = pthread_detach(threadId);
if (err)
std::cout << "Failed to detach Thread : " << strerror(err) << std::endl;
// Sleep for 2 seconds because if main function exits, then other threads will
// be also be killed. Sleep for 2 seconds, so that detached exits by then
sleep(2);
std::cout << "Main function ends " << std::endl;
return 0;
}
多線程導致的內存泄漏
#include<stdio.h>
#include<pthread.h>
void run() {
pthread_exit(0);
}
int main () {
pthread_t thread;
int rc;
long count = 0;
while(1) {
if(rc = pthread_create(&thread, 0, run, 0) ) {
printf("ERROR, rc is %d, so far %ld threads created\n", rc, count);
perror("Fail:");
return ‑1;
}
count++;
}
return 0;
}
編譯運行一下:
[root@server ~]# cc -lpthread thread.c -o thread
[root@server ~]# ./thread
ERROR, rc is 12, so far 304 threads created
Fail:: Cannot allocate memory
error code 是 12,啥意思呢,perror
函數幫我們打印出其含義:Cannot allocate memory
。很顯然,內存不夠了。
看看上面的代碼發現,創建的每一個線程既沒有調用pthread_join
讓主線程等待創建出來的線程退出以便清理其佔用的棧空間,也沒有用pthread_detach
讓線程自動清理佔用的空間。所有線程執行完後佔用空間不釋放,最終導致內存不足,造成了所謂的內存泄漏。
檢測泄漏
在調用pthread_create
時候如果不設定線程的 stack size,那麼 pthread_create 會使用 ulimit -s
中設置的大小作爲 stack size。
查看設置:
$ ulimit -s
8192
表示 8192KB,也就是 8MB。
grep 8192 一下 pmap 的輸出,然後 count 一下,就是進程所有的 thread 數(包括正在跑的進程和已經結束的 joinable 線程)。
pmap PID | grep 8192 | wc -l
而 通過:
ls /proc/PID/task | wc -l
得到的是正在運行的線程數。
對比一下兩者,如果前者一直比後者大,那麼可以考慮是 線程泄漏了。