目录
(3)SCHED_OTHER 分时调度策略(linux默认)
2、pthread_attr_setschedpolicy/pthread_attr_getschedpolicy(获取、设置线程的调度策略)
1、pthread_attr_setstacksize/pthread_attr_getstacksize(获取、设置线程栈大小、警戒区大小)
一、线程调度
1、三种调度算法
(1)SCHED_FIFO(先进先出的排队方式调度)
静态优先级设置为1-99,则线程如果处于就绪态,就能立即抢占静态优先级为0的普通线程。
a、就绪态时,放入优先级队列的队尾位置
b、被更高优先级的线程抢占之后,会被放入优先级队列的队头位置,当所有优先级比他高的线程不再运行后,就恢复运行
c、调用sched_yield()后,会被在优先级队列的队尾位置
总结:该线程会一直运行直到发送I/O请求,或者被更高优先级线程抢占,或者调用sched_yield()主动让出CPU
(2)SCHED_RR实时调度策略,时间片轮转
与SCHED_FIFO类似,区别在于设置了时间片,当时间片耗光时,会被在优先级队列的队尾位置,可以用sched_rr_get_interval( )来获得时间片的具体数值。
(3)SCHED_OTHER 分时调度策略(linux默认)
静态优先级必须设置为0
处于 0 优先级别的这些线程按照所谓的动态优先级被调度,而动态优先级起始于线程的 nice 值,且每当一个线程已处于就绪 态但被调度器调度无视时,其动态优先级会自动增加一个单位,这样能保证这些线程竞争 CPU 的公平性。
2、pthread_attr_setschedpolicy/pthread_attr_getschedpolicy(获取、设置线程的调度策略)
二、线程栈合警戒区
1、pthread_attr_setstacksize/pthread_attr_getstacksize(获取、设置线程栈大小、警戒区大小)
2、各个线程相对独立的栈
线程的栈可能溢出,需要增大栈空间,因为有警戒区,故不需要这么做,警戒区是没有任何访问权限的内存,用来保护相邻的两条线程的栈空间不被彼此践踏。
三、线程退出
1、pthread_exit(线程自己退出)
2、pthread_cancel(线程取消)(请线程退出)
某个时刻不能等某个线程“自然死亡”(例如在while(1)中),需要令其马上结束,可以给线程发送一个取消请求,让其中断执行退出。
而当线程收到一个取消请求时,他将会如何表现取决于两个东西:
一是当前的取消状态:
PTHREAD_CANCEL_ENABLE 使能 (允许取消。默认值) PTHREAD_CANCEL_DISABLE 失能 (不允许取消)
二是当前的取消类型:
延时响应 等待线程遇到取消点时响应取消的请求
立即响应
3、创建一个线程,在1s后发送取消线程的请求,线程终止
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
void * func (void * arg)
{
int * p = calloc(1,4);
while(1)
{
printf("这里是func线程,线程ID :%ld \n" , pthread_self() );
sleep(1);
}
*p = 1024 ;
// 退出本线程并设置返回值的地址(返回了num 的地址)
pthread_exit((void *)p); //返回的内存地址应该时一个堆空间
}
int main(int argc, char const *argv[])
{
// 创建线程
pthread_t t_id = -1 ;
pthread_create( &t_id , //新线程ID号
NULL , // 线程属性, NULL 默认属性
func, // 线程需要执行的例程(新线程需要执行的任务《函数》)
NULL ); // 线程的参数
printf("t_id : %ld\n" , t_id) ;
printf("这里是主函数,线程ID :%ld \n" , pthread_self() );
int * retval ;
int ret_val = 0 ;
sleep(1);
pthread_cancel( t_id );
// 阻塞等待接合线程
printf("等待 function 线程退出:\n");
if( ret_val = pthread_join( t_id , (void*)&retval))
{
fprintf(stderr , "接合失败:%s\n" , strerror(ret_val));
}
printf("结合线程成功, 退出值为:%d\n" , *retval);
// 尝试接合线程 (非阻塞)
// int ret_val = 0 ;
// if( ret_val = pthread_tryjoin_np( t_id , (void*)&retval))
// {
// fprintf(stderr , "接合失败:%s\n" , strerror(ret_val));
// }
return 0;
}
上述例子可以取消线程,但是没办法结合线程的退出值