网站建设原型,成都软件制作,东莞网站设计哪家好,深圳哪里有网站建设以下内容源于C语言中文网的学习与整理#xff0c;非原创#xff0c;如有侵权请告知删除。
如果只是学习简单的多线程编程#xff0c;本文内容可以暂时忽略。在利用pthread_create() 函数创建线程时#xff0c;第二个参数设置为NULL即可。 一、引入
通过阅读前面章节…以下内容源于C语言中文网的学习与整理非原创如有侵权请告知删除。
如果只是学习简单的多线程编程本文内容可以暂时忽略。在利用pthread_create() 函数创建线程时第二个参数设置为NULL即可。 一、引入
通过阅读前面章节我们已经学会了如果创建一个线程例如
#include pthread.h
void * threadFun(void* args){//......
}
pthread_t myThread;
pthread_create(myThread, NULL, ThreadFun, NULL);
其中pthread_create() 函数需要传递 4 个参数第二个参数 NULL 表示以系统默认的属性创建线程。那么线程都有哪些属性线程的属性又该如何设置或者修改呢 二、线程属性的种类
POSIX 标准中线程的属性用 pthread_attr_t 类型的变量表示举个例子
#include pthread.hpthread_attr_t myAttr;
上面我们就定义了一个表示线程属性的变量。
使用此变量前必须调用 pthread_attr_init() 函数进行初始化该函数的语法格式如下
int pthread_attr_init(pthread_attr_t * attr);
此函数定义在 pthread.h 头文件中函数执行成功时返回数字 0反之返回非零数。
例如对 myAttr 变量进行初始化
pthread_attr_init(myAttr);
通过调用 pthread_attr_init() 函数myAttr 变量就拥有了系统默认的线程属性。在此基础上我们可以根据需要对 myAttr 变量的属性值进行修改。 在利用pthread_create() 函数创建线程时将这个修改后的变量放在第二个参数位置即可。 pthread_attr_t 是一种结构体类型内部包含多种线程属性
typedef struct
{int __detachstate;int __schedpolicy;struct sched_param __schedparam;int __inheritsched;int __scope;size_t __guardsize;int __stackaddr_set;void* __stackaddr;size_t __stacksize;
} pthread_attr_t;
接下来我们将从中挑选出几个常用的属性给您讲解它们的功能以及修改的方法。
1) __detachstate
我们知道默认属性的线程在执行完目标函数后占用的私有资源并不会立即释放要么执行完 pthread_join() 函数后释放要么整个进程执行结束后释放。某些场景中我们并不需要接收线程执行结束后的返回值如果想让线程执行完后立即释放占用的私有资源就可以通过修改 __detachstate 属性值来实现。
__detachstate 属性值用于指定线程终止执行的时机该属性的值有两个分别是
PTHREAD_CREATE_JOINABLE默认值表示线程执行完函数后不会自行释放资源PTHREAD_CREATE_DETACHED线程执行完函数后会自行终止并释放占用的资源。
关于 __detachstate 属性pthread.h 头文件中提供了 2 个与它相关的函数分别是
int pthread_attr_getdetachstate(const pthread_attr_t * attr,int * detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *sttrint detachstate);
pthread_attr_getdetachstate() 函数用于获取 __detachstate 属性的值detachstate 指针用于接收 __detachstate 属性的值
pthread_attr_setdetachstate() 函数用于修改 __detachstate 属性的值detachstate 整形变量即为新的 __detachstate 属性值。
两个函数执行成功时返回数字 0反之返回非零数。 此外pthread.h 头文件还提供有 pthread_detach() 函数可以直接将目标线程的 __detachstate 属性改为 PTHREAD_CREATE_DETACHED语法格式如下
int pthread_detach(pthread_t thread);
函数执行成功时返回数字 0 反之返回非零数。
2) __schedpolicy
__schedpolicy 属性用于指定系统调度该线程所用的算法它的值有以下 3 个
SCHED_OTHER默认值分时调度算法SCHED_FIFO先到先得实时调度算法SCHED_RR轮转法 其中SCHED_OTHER 调度算法不支持为线程设置优先级而另外两种调度算法支持。 pthread.h 头文件提供了如下两个函数专门用于访问和修改 __schedpolicy 属性
int pthread_attr_getschedpolicy(const pthread_attr_t *, int * policy)
int pthread_attr_setschedpolicy(pthread_attr_*, int policy)
pthread_attr_getschedpolicy() 函数用于获取当前 __schedpolicy 属性的值;
pthread_attr_setschedpolicy() 函数用于修改 __schedpolicy 属性的值。函数执行成功时返回值为数字 0反之返回非零数。
3) __schedparam
__scheparam 用于设置线程的优先级默认值为 0该属性仅当线程的 __schedpolicy 属性为 SCHED_FIFO 或者 SCHED_RR 时才能发挥作用。
pthread.h 头文件中提供了如下两个函数用于获取和修改 __schedparam 属性的值
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
其中param 参数用于接收或者修改 __scheparam 属性的优先级它是 sched_param 结构体类型的变量定义在 sched.h 头文件中内部仅有一个 sched_priority 整形变量用于表示线程的优先级。函数执行成功时返回数字 0反之返回非零数。 当需要修改线程的优先级时我们只需创建一个 sched_param 类型的变量并为其内部的 sched_priority 成员赋值然后将其传递给 pthrerd_attr_setschedparam() 函数。 不同的操作系统线程优先级的值的范围不同您可以通过调用如下两个系统函数获得当前系统支持的最大和最小优先级的值
int sched_get_priority_max(int policy); //获得最大优先级的值
int sched_get_priority_min(int policy); //获得最小优先级的值
其中policy 的值可以为 SCHED_FIFO、SCHED_RR 或者 SCHED_OTHER当 policy 的值为 SCHED_OTHER 时最大和最小优先级的值都为 0。
4) __inheritsched
新建线程的调度属性____schedpolicy 和 __schedparam 属性默认遵循父线程的属性谁创建它谁就是它的父线程如果我们想自定义线程的调度属性就需要借助 __inheritsched 属性。
也就是说新线程的调度属性要么遵循父线程要么遵循 myAttr 规定的属性默认情况下 __inheritsched 规定新线程的调度属性遵循父线程我们也可以修改 __inheritsched 的值使新线程的调度属性遵循自定义的属性变量如文章开头定义的 myAttr规定的值。
pthread.h 头文件提供了如下两个函数分别用于获取和修改 __inheritsched 属性的值
//获取 __inheritsched 属性的值
int pthread_attr_getinheritsched(const pthread_attr_t *attr,int *inheritsched);
//修改 __inheritsched 属性的值
int pthread_attr_setinheritsched(pthread_attr_t *attr,int inheritsched);
其中在 pthread_attr_setinheritsched() 函数中inheritsched 参数的可选值有两个分别是
PTHREAD_INHERIT_SCHED默认值新线程的调度属性继承自父线程PTHREAD_EXPLICIT_SCHED新线程的调度属性继承自 myAttr 规定的值。
以上两个函数执行成功时返回数字 0反之返回非零数。
5) __scope
线程执行过程中可以只和同进程内的其它线程争夺 CPU 资源也可以和系统中所有的其它线程争夺 CPU 资源__scope 属性用于指定目标线程和哪些线程抢夺 CPU 资源。
pthread.h 头文件中提供了如下两个函数分别用于获取和修改 __scope 属性的值
//获取 __scope 属性的值
int pthread_attr_getscope(const pthread_attr_t * attr,int * scope);
//修改 __scope 属性的值
int pthread_attr_setscope(pthread_attr_t * attr,int * scope);
当调用 pthread_attr_setscope() 函数时scope 参数的可选值有两个分别是
PTHREAD_SCOPE_PROCESS同一进程内争夺 CPU 资源PTHREAD_SCOPE_SYSTEM系统所有线程之间争夺 CPU 资源。 Linux系统仅支持 PTHREAD_SCOPE_SYSTEM即所有线程之间争夺 CPU 资源。 当函数执行成功时返回值为数字 0反之返回非零数。
6) __stacksize
每个线程都有属于自己的内存空间通常称为栈有时也称堆栈、栈空间、栈内存等。某些场景中线程执行可能需要较大的栈内存此时就需要我们自定义线程拥有的栈的大小。
__stacksize 属性用于指定线程所拥有的栈内存的大小。pthread.h 提供有以下两个函数分别用于获取和修改栈空间的大小
//获取当前栈内存的大小
int pthread_attr_getstacksize(const pthread_attr_t * attr,size_t * stacksize);
//修改栈内存的大小
int pthread_attr_setsstacksize(pthread_attr_t * attr,size_t * stacksize);
函数执行成功时返回值为数字 0反之返回非零数。
8) __guardsize
每个线程中栈内存的后面都紧挨着一块空闲的内存空间我们通常称这块内存为警戒缓冲区它的功能是一旦我们使用的栈空间超出了额定值警戒缓冲区可以确保线程不会因“栈溢出”立刻执行崩溃。
__guardsize 属性专门用来设置警戒缓冲区的大小pthread.h 头文件中提供了如下两个函数分别用于获取和修改 __guardsize 属性的值
int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,size_t *restrict guardsize);
int pthread_attr_setguardsize(pthread_attr_t *attr ,size_t *guardsize);
pthread_attr_setguardsize() 函数中设置警戒缓冲区的大小为参数 guardsize 指定的字节数。函数执行成功时返回数字 0反之返回非零数。 三、代码示例
接下来通过一个样例给大家演示如何自定义线程的属性
#include stdio.h
#include stdlib.h
#include pthread.h
#include errno.h
//myThread1 线程执行的函数
void *Thread1(void *arg)
{printf(Thread1 正在执行\n);printf(http://c.biancheng.net\n);printf(Thread1 执行完毕\n);return NULL;
}
//myThread2 线程执行的函数
void* Thread2(void* arg)
{printf(Thread2 正在执行\n);printf(C语言中文网\n);printf(Thread2 执行完毕\n);return NULL;
}int main(int argc,char *argv[])
{int num1, num2, res;//创建两个线程pthread_t mythread1, mythread2;//创建两个表示线程优先级的变量struct sched_param param1, param2;//创建两个表示线程属性的变量pthread_attr_t myAttr1, myAttr2;//接收 2 个整数用于设定线程的优先级if (argc ! 3) {printf(未向程序传入 2 个表示优先级的数字\n);return 0;}//初始化线程属性res pthread_attr_init(myAttr1);if (res ! 0) {printf(myAttr1 init Fail\n);}res pthread_attr_init(myAttr2);if (res ! 0) {printf(myAttr1 init Fail\n);}//设置 myAttr1 的 __detachstate 属性值为 PTHREAD_CREATE_DETACHED//遵循 myAttr1 属性的线程执行函数完毕后会自行释放占用私有资源不支持 pthread_join() 函数res pthread_attr_setdetachstate(myAttr1, PTHREAD_CREATE_DETACHED);if (res ! 0) {printf(myAttr1 set_detachstate Fail\n);}//设置 myAttr1 的 __scope 属性值为 PTHREAD_SCOPE_SYSTEM//遵循 myAttr1 属性的线程将同系统中的所有其它线程争夺 CPU 资源res pthread_attr_setscope(myAttr1, PTHREAD_SCOPE_SYSTEM);if (res ! 0) {printf(myAttr1 set_scope Fail\n);}//设置 myAttr2 的 __scope 属性值为 PTHREAD_SCOPE_SYSTEM//遵循 myAttr2 属性的线程将同系统中的所有其它线程争夺 CPU 资源res pthread_attr_setscope(myAttr2, PTHREAD_SCOPE_SYSTEM);if (res ! 0) {printf(myAttr2 set_scope Fail\n);}//设置 myAttr1 的 __schedpolicy 属性值为 SCHED_FIFO//系统会以实时调用的方式执行遵循 myAttr1 属性的线程res pthread_attr_setschedpolicy(myAttr1, SCHED_FIFO);if (res ! 0) {printf(myAttr1 set_policy Fail\n);}//设置 myAttr2 的 __schedpolicy 属性值为 SCHED_FIFO//系统会以实时调用的方式执行遵循 myAttr2 属性的线程res pthread_attr_setschedpolicy(myAttr2, SCHED_FIFO);if (res ! 0) {printf(myAttr2 set_policy Fail\n);}//设置 myAttr1 的 __inheritsched 属性值为 PTHREAD_EXPLICIT_SCHED//myAttr1 属性的线程将遵循自定义的线程属性res pthread_attr_setinheritsched(myAttr1, PTHREAD_EXPLICIT_SCHED);if (res ! 0) {printf(myAttr1 set_inheritsched fail\n);}//设置 myAttr2 的 __inheritsched 属性值为 PTHREAD_EXPLICIT_SCHED//myAttr2 属性的线程将遵循自定义的线程属性res pthread_attr_setinheritsched(myAttr2, PTHREAD_EXPLICIT_SCHED);if (res ! 0) {printf(myAttr2 set_inheritsched fail\n);}//想 argv[] 数组中的字符转换为数字num1 atoi(argv[1]);num2 atoi(argv[2]);// 分别将 num1 和 num2 作为线程优先级的值param1.sched_priority num1;param2.sched_priority num2;//设置 myAttr1 属性的优先级为 param1res pthread_attr_setschedparam(myAttr1, param1);if (res ! 0) {printf(param1 setscheparam Fail\n);}//设置 myAttr2 属性的优先级为 param2res pthread_attr_setschedparam(myAttr2, param2);if (res ! 0) {printf(param2 setscheparam Fail\n);}//创建新线程并遵循 myAttr1 属性res pthread_create(mythread1, myAttr1, Thread1, NULL);if (res ! 0) {printf(mythread1 create Fail\n);}//创建新线程并遵循 myAttr2 属性res pthread_create(mythread2, myAttr2, Thread2, NULL);if (res ! 0) {printf(mythread2 create Fail\n);}sleep(5); //等待 mythread1 和 mythread2 两个线程执行完//尝试 pthread_join() 函数等待 mythread1 线程执行结束res pthread_join(mythread1, NULL);if (res ! 0) {if (res EINVAL) {printf(mythread1不支持调用 pthread_join()函数\n);}}//尝试等待 mythread2 线程执行结束res pthread_join(mythread2, NULL);if (res ! 0) {printf(mythread2 has finished\n);}printf(主线程执行完毕\n);return 0;
}
假设程序编写在 thread.c 文件中执行过程如下
[rootlocalhost ~]# gcc thread.c -o thread.exe -lpthread
[rootlocalhost ~]# ./thread.exe 30 3
Thread1 正在执行
http://c.biancheng.net
Thread1 执行完毕
Thread2 正在执行
C语言中文网
Thread2 执行完毕
mythread1不支持调用 pthread_join()函数
主线程执行完毕
[rootlocalhost ~]# ./thread.exe 3 30
Thread2 正在执行
C语言中文网
Thread2 执行完毕
Thread1 正在执行
http://c.biancheng.net
Thread1 执行完毕
mythread1不支持调用 pthread_join()函数
主线程执行完毕
上面展示了两组执行结果分别为 mythread1 和 mythread2 设置了不同的优先级从运行结果可以看到哪个线程的优先级高数值大哪个线程先执行。
此外通过程序的执行结果还可以看出由于 mythread 线程的 __detachstate 属性为 PTHREAD_CREATE_DETACHED因此该线程执行完 Thread1() 函数后会自行终止并释放占用的私有资源不需要也不允许在其它线程比如主线程中执行 pthread_join(mythread1, NULL) 函数。