1. 程式人生 > >linux——pthread_create()到底可以建立多少個執行緒?

linux——pthread_create()到底可以建立多少個執行緒?

pthread_create()到底可以建立多少個執行緒?

今天在檢視pthread_create()函式的使用方法時,比較好奇它到底可以建立多少個執行緒呢?下面就來測試一番,以下是測試過程。

#include <pthread.h>

#include <stdio.h>

#include <string.h>

#include <unistd.h>

void *ThreadFunc()
{
    static int count = 1;
    printf ("Create thread %d\n", count);
    count++;
}
main(void)

{
    int     err;
    pthread_t tid;
    while (1)
    {
           err= pthread_create(&tid, NULL, ThreadFunc, NULL);
           if(err != 0){
               printf("can't create thread: %s\n",strerror(err));
           break;
           }
          usleep(2000);
    }
}

編譯,執行:

gcc pthread_test.c  -o pthread_test  -lpthread
./pthread_test 

執行結果如下:
在這裡插入圖片描述
可以看到linux在建立了381後進程後,報錯;Resource temporarily unavailable,資源暫時不可用。那為什麼會是381個呢?我們可以使用ulimit -a 來檢視自己系統預設設定中執行緒棧的大小,如下:
在這裡插入圖片描述
可以看到,stack size 是8192K,及8M。max user processer 是7864個。為什麼建立了381個就滿了呢?下面看下計算過程:
32位linux下的程序使用者空間是3G,即3072M, 3072 M/8M=384個。為什麼實際只能建立381呢?這個實際原因還沒找到,有知道的網友可以留言告知一下。

修改執行緒預設棧空間大小

(1)以下是linux檢視並修改執行緒預設棧空間大小的一些方法:
a、通過命令 ulimit -s 檢視linux的預設棧空間大小,預設情況下 為8192即8M

b、通過命令 ulimit -s 設定大小值 臨時改變棧空間大小:ulimit -s 10240, 即修改為10M

c、可以在/etc/rc.local 內 加入 ulimit -s 10240 則可以開機就設定棧空間大小為10M

d、在/etc/security/limits.conf 中也可以改變棧空間大小:
增加設定:
soft stack 10240
重啟後,執行ulimit -s 即可看到改為10240 即10M。
(2)那為啥linux要限制使用者程序的棧記憶體大小?
Why does Linux have a default stack size soft limit of 8 MB?
The point is to protect the OS.
Programs that have a legitimate reason to need more stack are rare. On the other hand, programmer mistakes are common, and sometimes said mistakes lead to code that gets stuck in an infinite loop. And if that infinite loop happens to contain a recursive function call, the stack would quickly eat all the available memory. The soft limit on the stack size prevents this: the program will crash but the rest of the OS will be unaffected.

Note that as this is only a soft limit, you can actually modify it from within your program (see setrlimit(2): get/set resource limits) if you really need to.

執行緒資源的回收

(3)每次用完程序後都自動的回收資源,繼續測試結果:

#include <pthread.h>

#include <stdio.h>

#include <string.h>

#include <unistd.h>

void *ThreadFunc()
{
    static int count = 1;
    printf ("Create thread %d\n", count);
    pthread_detach(pthread_self()); //標記為DETACHED狀態,完成後釋放自己佔用的資源。
    count++;
}
main(void)
{
    int     err;
    pthread_t tid;
    while (1)
    {
           err= pthread_create(&tid, NULL, ThreadFunc, NULL);
           if(err != 0){
               printf("can't create thread: %s\n",strerror(err));
           break;
           }
          usleep(2000);
    }
}

在這裡插入圖片描述
可以看到程式一直在無限迴圈建立執行緒,只能使用ctrl+c暫停了。也就是說如我們每次用完執行緒就釋放點資源,是可以建立無限個執行緒的。執行緒資源的回收主要有兩種:
(a)某個執行緒完成後,自己主動釋放掉資源。使用pthread_detach ( pthread_self ( ) )來釋放執行緒所佔用的記憶體資源(執行緒核心物件和執行緒堆疊)。這樣就可以建立更多的執行緒,而不會出現資源暫時不可用的錯誤了。
如果程序中的某個執行緒執行了pthread_detach(th),則th執行緒將處於DETACHED狀態,這使得th執行緒在結束執行時自行釋放所佔用的記憶體資源。
(b) 某個執行緒完成後,另一個執行緒來釋放這個執行緒的資源。在另一個執行緒B中呼叫 int pthread_join(pthread_t thread, void **retval)函式,B執行緒會一直等待A執行緒完成,當A執行緒執行完後,B會把A執行緒的資源回收回去。舉個簡單的例子,如下;

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
 
void printids(const char *s)
{
    pid_t pid;
    pthread_t tid;
    pid = getpid();
    tid = pthread_self();
    printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int) pid,
            (unsigned int) tid, (unsigned int) tid);
}
 
void *thr_fn(void *arg)
{
    printids("new thread: ");
    return NULL;
}
 
int main(void)
{
    int err;
    pthread_t ntid;
    err = pthread_create(&ntid, NULL, thr_fn, NULL);
    if (err != 0)
        printf("can't create thread: %s\n", strerror(err));
    printids("main thread:");
    pthread_join(ntid,NULL);
    return EXIT_SUCCESS;
}

gcc main.c -o main
./main
執行結果:
main thread: pid 13073 tid 3077572816 (0xb77008d0)
new thread: pid 13073 tid 3077569392 (0xb76ffb70)
main thread會一直等待new thread完成,待其完成後,把new thread資源釋放掉。
所以我們在使用執行緒時,注意使用pthread_detach()或pthread_join ()釋放掉使用的執行緒資源,防止記憶體棧的洩漏。