本文将通过一个创建n个线程的案例来展示一下线程属性的设定及使用,通常情况下,系统对于线程的创建是没有限制的,但是每一个线程都是需要一个栈空间的,每个栈空间大小也都是固定的,可通过系统命令 ulimit -a 来查看,如果线程栈空间的总数超过了一个进程可使用的虚拟内存用户空间,那么就无法再继续创建线程了。我们只是做一个小的测试,调整每个线程的栈空间大小来揭露线程属性的使用方法,并提高一个程序创建线程的数量(Notice:提高线程数量并没有什么好处,我们只是为了演示如何修改线程属性)。


【普通的创建线程案例】

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

void* dowork()
{
while(1)
{
sleep(1);
}
}

int main(int argc, char* argv[])
{
int i = 0;
int res;
pthread_t tid;
while(1){
// 无限创建线程,直到遇到错误为止
if((res = pthread_create(&tid, NULL, dowork, NULL)))
{
printf(“%s\n”, strerror(res));
break;
}
// 每成功创建一个线程将 i++
i++;
}
// 最后打印 i 的值
printf(“%d\n”, i);
return 0;
}

该程序运行后,效果如下图: 2015-07-05_165151 程序最终创建了 381 个线程,每个线程使用的栈大小是系统默认的,这个默认值可以如下: 2015-07-05_165338 381 * 8192Byte = 3121152Byte,只是字节数 Byte,3121152Byte / 1024Byte = 3048MB 得到的是 KByte,而每个进程可使用的虚拟内存用户空间的大小是 3GB (1024 * 3)= 3072MB。可以看出,我们的程序已经快将虚拟内存用户空间使用完了,所以程序再次分配线程失败了。


而如果我们将每一个线程的栈大小设定的更小了(线程属性设置),是不是就可以提高创建线程的数量呢?看如下代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define STACK_SIZE 1024 * 1024

void* dowork()
{
while(1)
{
sleep(1);
}
}

int main(int argc, char* argv[])
{
int i = 0;
int res;
char* pStack;
pthread_t tid;
// 初始化线程属性结构
pthread_attr_t attr;
pthread_attr_init(&attr);
// 设定线程属性为分离属性
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

while(1){
// 分配栈空间
pStack = malloc(STACK_SIZE);
if (NULL == pStack) break;
// 设置线程栈大小
pthread_attr_setstack(&attr, pStack, STACK_SIZE);
// 创建线程
if((res = pthread_create(&tid, &attr, dowork, NULL)))
{
printf(“%s\n”, strerror(res));
break;
}
i++;
}
// 销毁线程属性结构
pthread_attr_destroy(&attr);
printf(“%d\n”, i);
return 0;
}

程序将线程的栈大小调整为 1024Byte * 1024Byte = 1MB,然后再次循环创建线程,效果如下图: 2015-07-05_170330 程序最终创建了 3055 个线程,每个线程  1MB * 3055 = 3055MB,也逼近了可使用的虚拟内存用户空间的大小。至此我们验证了线程数量的创建取决于栈大小并且学会了如何设定一个线程的属性。