Linux之线程Thread小结

文章目录

  • 线程相关操作函数
    • pthread_create 创建新新程
    • 获取线程ID
    • 线程终止
    • 线程等待
    • 分离线程
    • 线程同步
      • 互斥锁
      • 条件变量
      • 读写锁
      • 信号量
  • 线程私有数据
  • 线程属性
    • 属性操作函数
      • 线程属性创建和销毁
      • 线程继承属性
      • 线程调度策略
      • 线程调度参数
      • 线程的作用域
      • 线程分离和非分离属性
      • 线程堆栈地址
      • 线程栈地址和大小
      • 线程栈大小
      • 线程栈保护区大小
    • 线程的作用域(scope)
    • 线程的绑定状态(binding state)
    • 线程的分离状态(detached state)
    • 线程优先级(priority)
    • 线程的栈地址(stack address)
    • 线程的栈大小(stack size)
    • 线程的栈保护区大小(stack guard size)
    • 线程的调度策略(schedpolicy)
    • 线程并行级别(concurrency)

线程相关操作函数

struct task_struct {
...
pid_t pid;//线程id
pid_t tgid;//进程id
...
struct task_struct *group_leader;//主线程
...
struct list_head thread_group;//线程组
...
};

获取线程ID:pid_t gettid(void)
获取进程ID:pid_t getpid(void)

pthread_create 创建新新程

/*
thread:返回线程ID//这里用的是pthread_self获得tid号
attr:设置线程的属性,attr为NULL表示使用默认属性
start_routine:函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数
成功返回0,失败返回错误码
*/
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);

获取线程ID

/*
*获取POSIX描述的线程ID
*用来区分某个进程中不同的线程,当一个线程退出后,新创建的线程可以复用原来的id
*/
pthread_t pthread_self(void);
/*
*gettid获取的是内核中线程ID
*对于单线程的进程,内核中tid=pid;对于多线程进程,pid相同tid不同;tid用于描述内核真实的pid和tid信息
*/
pid_t gettid(void);

线程终止

  • 线程函数return
    如果return返回指针,则指针所指向的内存单元必须是全局的或者malloc分配的
  • 调用pthread_exit终止自己
/*
*pthread_exit返回的指针所指向的内存单元必须是全局的或者malloc分配的
*/
void pthread_exit(void *value_ptr);
  • 一个线程可以调用pthread_cancel终止同一个进程中的另一个线程
    被取消的线程,退出值,是定义在Linux的pthread库中常数PTHREAD_CANCELED的值(-1)
/*
*thread:线程ID
*成功返回0,失败返回错误码
*系统并不会马上关闭被取消线程,只有在被取消线程下次系统调用时,才会真正结束线程
*若线程函数没有系统调用,则在线程函数中调用pthread_testcancel(),让内核去检测是否需要取消当前线程
*/
int pthread_cancel(pthread_t thread);

线程等待

/*
*thread:线程ID
*value_ptr:指向一个指针,指向线程的返回值
*成功返回0,失败返回错误码
*/
//如果对thread线程的终止状态不感兴趣,可以传NULL给value_ ptr参数
int pthread_join(pthread_t thread, void **value_ptr);
  • 调用该函数的线程将挂起等待,直到id为thread的线程以不同的方式终止
  • 如果thread线程通过return返回,value_ ptr所指向的单元⾥里存放的是thread线程函数的返回值
  • 如果thread线程被别的线程调用pthread_ cancel异常终掉,value_ ptr所指向的单元⾥里存放的是常数 PTHREAD_ CANCELED
  • 如果thread线程是自己调用pthread_exit 终止的 ,valueptr所指向的单元存放的是传给pthread_exit的参数

分离线程

pthread_detach(pthread_t thread);
  • 也可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离
    pthread_detach(pthread_self);
  • 默认情况下,新创建的线程是等待的,线程退出后,需要对其pthread_join操作的,否则无法释放资源,从而造成系统泄露,如果不关心线程的返回值,pthread_detach告诉系统,当线程退出时,自动释放线程资源
  • pthread_detach和pthread_join是冲突的,一个线程不能同时进行joinable和分离

线程同步

互斥锁

#include 
pthread_mutex_t mutex_x = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);

初始化:

//静态
pthread_mutex_t mutex_x=PTHREAD_MUTEX_INITIALIZER;
//动态
/*
*参数attr指定了新建互斥锁的属性。若参数attr为空(NULL),则使用默认的互斥锁属性,默认属性为快速互斥锁
*成功返回0,失败返回错误码
*/
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);

互斥锁相关属性

//初始化互斥锁属性
pthread_mutexattr_init(pthread_mutexattr_t attr);
//销毁互斥锁属性
pthread_mutexattr_destroy(pthread_mutexattr_t attr);
//用于获取互斥锁属性
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr , int *restrict pshared);
//用于设置互斥锁属性
/*属性值:
*PTHREAD_PROCESS_PRIVATE:锁只能用于一个进程内部的两个线程进行互斥(默认情况)
*PTHREAD_PROCESS_SHARED:锁可用于两个不同进程中的线程进行互斥,使用时还需要在进程共享内存中分配互斥锁,然后为该互斥锁指定属性
*/
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr , int pshared);
//获取互斥锁类型
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr , int *restrict type);
//设置互斥锁类型
/*类型:
*PTHREAD_MUTEX_NOMAL:标准互斥锁,第一次上锁成功,第二次上锁会失败并阻塞
*PTHREAD_MUTEX_RECURSIVE:递归互斥锁,第一次上锁成功,第二次上锁还是会成功,可以理解为内部有一个计数器,每加一次锁计数器加1,解锁减1
*PTHREAD_MUTEX_ERRORCHECK:检查互斥锁,第一次上锁会成功,第二次上锁出错返回错误信息,不会阻塞
*PTHREAD_MUTEX_DEFAULT:默认互斥锁,第一次上锁会成功,第二次上锁会失败
*/
int pthread_mutexattr_settype(const pthread_mutexattr_t *restrict attr , int type);

条件变量

  • 当线程在等待满足某些条件时使线程进入睡眠状态,一旦条件满足,就换线因等待满足特定条件而睡眠的线程
  • 条件变量必须是全局变量,而且必须在互斥锁保护下使用
#include
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;   //cond
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;  //mutex
/*
*函数将解锁mutex参数指向的互斥锁,并使当前线程阻塞cv参数指向的条件变量上
*被阻塞的线程可以被pthread_cond_signal、pthread_cond_broadcast函数唤醒,也可以被信号中断后唤醒
*pthread_cond_wait函数的返回并不意味条件满足,必须重新检查条件的值
*pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,即使函数出错返回
*成功返回0,失败返回失败码
*/
int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex);
/*
*函数到一定时间,即使条件未发生也会解除阻塞
*pthread_cond_timedwait函数也是退出点
*成功返回0,失败返回失败码
*/
int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mp, const structtimespec * abstime);
/*
*用于释放被阻塞在指定条件变量上的一个线程
*必须在互斥锁的保护下使用相应的条件变量,否则很容易造成死锁
*成功返回0,失败返回出错码
*/
int pthread_cond_signal(pthread_cond_t *cv);
/*
*函数唤醒所有被pthread_cond_wait函数阻塞在某个条件变量上的线程
*参数cv被用来指定这个条件变量,当没有线程阻塞在这个条件变量上时,pthread_cond_broadcast函数无效
*成功返回0,失败返回出错码
*/
int pthread_cond_broadcast(pthread_cond_t *cv);
/*
成功返回0,失败返回错误码
*/
int pthread_cond_destroy(pthread_cond_t *cv);

初始化:

//静态
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
//动态
/*
*参数cattr指定了新建条件变量的属性。若参数attr为空(NULL),则默认缺省的条件变量
*成功返回0,失败返回错误码
*/
int pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t *cattr);

唤醒丢失问题

  • 在线程未获得相应的互斥锁时调用pthread_cond_signal或pthread_cond_broadcast函数可能会引起唤醒丢失问题

唤醒丢失往往会在下面的情况下发生:

  • 一个线程调用pthread_cond_signal或pthread_cond_broadcast函数
  • 另一个线程正处在测试条件变量和调用pthread_cond_wait函数之间
  • 没有线程正在处在阻塞等待的状态下

读写锁

可以多个线程同时读,但是不能多个线程同时写

  • 读写锁比互斥锁更加具有适用性和并行性
  • 读写锁最适用于对数据结构的读操作读操作次数多余写操作次数的场合
  • 锁处于读模式时可以线程共享,而锁处于写模式时只能独占,所以读写锁又叫做共享-独占锁
  • 读写锁有两种策略:强读同步和强写同步
  • 在强读同步中,总是给读者更高的优先权,只要写者没有进行写操作,读者就可以获得访问权限
#include
//静态初始化
pthread_rwlock_t rwlock=PTHREAD_RWLOCK_INITIALIZER;
//动态初始化,NULL代表读写锁采用默认属性
int pthread_rwlock_init(rwlock,NULL);
//销毁读写锁
/*
*在释放某个读写锁的资源之前,需要先通过pthread_rwlock_destory函数对读写锁进行清理。释放由pthread_rwlock_init函数分配的资源
*/
int pthread_rwlock_destory(rwlock);

/*
如果你想要读写锁使用非默认属性,则attr不能为NULL,得给attr赋值
*/
//给attr初始化
int pthread_rwlockattr_init(attr);
//销毁attr
int pthread_rwlockattr_destory(attr);

/*
*以写的方式获取锁,以读的方式获取锁,释放读写锁
*
*/
//以读的方式获取锁
int pthread_rwlock_rdlock(rwlock);
//以写的方式获取锁
int pthread_rwlock_wrlock(rwlock);
//释放锁
int pthread_rwlock_unlock(rwlock);
//上面两个获取锁的方式都是阻塞的函数,也就是说获取不到锁的话
//调用线程不是立即返回,而是阻塞执行
//在需要进行写操作的时候,这种阻塞式获取锁的方式是非常不好的

/*非阻塞的方式获取锁*/
int pthread_rwlock_tryrdlock(rwlock);
int pthread_rwlock_trywrlock(rwlock);

信号量

struct sem {
	int	semval;	/* 信号量的当前值 */
	int	sempid;	/* 上一次操作本信号的进程PID */
};

信号量(sem)和互斥锁的区别:互斥锁只允许一个线程进入临界区,而信号量允许多个线程进入临界区

#include
sem_t sem;
//信号量初始化
/*
*pshared为0表示这个信号量是当前进程的局部信号量
*pshared为1表示这个信号量可以在多个进程之间共享
*v为信号量的初始值
*成功返回0,失败返回-1
*/
int sem_init(&sem,pshared,v);

//信号量值的加减
//以原子操作的方式将信号量的值减去1
int sem_wait(&sem);
//以原子操作的方式将信号量的值加上1
int sem_post(&sem);

//对信号量进行清理
int sem_destory(&sem)

线程私有数据

具体用法:

  • 创建一个类型为pthread_key_t类型的变量
  • 调用pthread_key_create()来创建该变量。该函数有两个参数,第一个参数就是上面声明的pthread_key_t变量,第二个参数是一个清理函数,用来在线程释放该线程存储的时候被调用。该函数指针可以设成NULL,这样系统将调用默认的清理函数
  • 当线程中需要存储特殊值的时候,可以调用pthread_setspcific()。该函数有两个参数,第一个为前面声明的pthread_key_t变量,第二个为void*变量,这样你可以存储任何类型的值
  • 如果需要取出所存储的值,调用pthread_getspecific()。该函数的参数为前面提到的pthread_key_t变量,该函数返回void *类型的值
//创建和注销 
/*
*不论哪个线程调用pthread_key_create(),所创建的key都是所有线程可访问的
*但各个线程可根据自己的需要往key中填入不同的值,这就相当于提供了一个同名而不同值的全局变量
*/
int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *));
/*
*在LinuxThreads的实现中,TSD池用一个结构数组表示
*创建一个线程私有数据就相当于将结构数组中的某一项设置为"in_use",并将其索引返回给*key,然后设置destructor函数为destr_function
*/
static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] = {{0, NULL}};
/*
*函数并不检查当前是否有线程正使用该线程私有数据,也不会调用清理函数(destr_function)
*而只是将TSD释放以供下一次调用pthread_key_create()使用。
*在LinuxThreads中,它还会将与之相关的线程数据项设为NULL
*/
int pthread_key_delete(pthread_key_t key);
//访问私有变量
int pthread_setspecific(pthread_key_t key, const void *pointer); 
void * pthread_getspecific(pthread_key_t key);

线程属性

//pthread.h
struct sched_param {
	int sched_priority;
};
typedef struct
{
	int etachstate; //线程的分离状态
    int schedpolicy; //线程调度策略
    struct sched_param schedparam; //线程的调度参数
    int inheritsched; //线程的继承性
    int scope; //线程的作用域
    size_t guardsize; //线程栈末尾的警戒缓冲区大小
    int stackaddr_set; //线程的栈设置
    void*  stackaddr; //线程栈的位置
    size_t stacksize; //线程栈的大小
}pthread_attr_t;
  • 属性值不能直接设置,须使用相关函数进行操作
  • 初始化的函数为pthread_attr_init,且必须在pthread_create函数之前调用
  • 线程退出后,须用pthread_attr_destroy函数来释放资源
  • 线程属性主要包括:作用域(scope)、栈尺寸(stack size)、栈地址(stack address)、优先级(priority)、分离的状态(detached state)、调度策略和参数(scheduling policy and parameters)
  • 默认的属性为非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级

属性操作函数

线程属性创建和销毁

//应先初始化线程属性,再pthread_create创建线程
/*
*初始化线程属性
*成功返回0,失败返回错误码
*/
int pthread_attr_init(pthread_attr_t *attr);
/*
*销毁线程属性所占用的资源
*成功返回0,失败返回错误码
*/
int pthread_attr_destroy(pthread_attr_t *attr);

线程继承属性

/*
*获得/设置线程的继承性
*attr:线程属性变量
*inheritsched:线程的继承性
*若成功返回0,若失败返回-1
*继承性的可能值是PTHREAD_INHERIT_SCHED,表示新现成将继承创建线程的调度策略和参数
*PTHREAD_EXPLICIT_SCHED(缺省),表示使用在schedpolicy和schedparam属性中显式设置的调度策略和参数
*/
int pthread_attr_getinheritsched(const pthread_attr_t *attr,int *inheritsched);
int pthread_attr_setinheritsched(pthread_attr_t *attr,int inheritsched);

线程调度策略

/*
*获得/设置线程的调度策略
*attr:线程属性变量
*policy:调度策略
*若成功返回0,若失败返回-1
*调度策略可能的值是先进先出(SCHED_FIFO)、轮转法(SCHED_RR),或其它(SCHED_OTHER)
*/
int pthread_attr_getschedpolicy(const pthread_attr_t *attr,int *policy);
int pthread_attr_setschedpolicy(pthread_attr_t *attr,int policy);

线程调度参数

/*
*大的优先权值对应高的优先权
*系统支持的最大和最小优先权值可以用sched_get_priority_max函数和sched_get_priority_min函数分别得到
*policy:系统支持的线程优先权的最大和最小值
*若成功返回0,若失败返回-1
*/
struct sched_param
{
	int sched_priority;
};
int sched_get_priority_max(int policy);
int sched_get_priority_min(int policy);
/*
*获得/设置线程的调度参数
*attr:线程属性变量
*param:ched_param结构
*/
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);

如果不是编写实时程序,不建议修改线程的优先级。因为,调度策略是一件非常复杂的事情,如果不正确使用会导致程序错误,从而导致死锁等问题。如:在多线程应用程序中为线程设置不同的优先级别,有可能因为共享资源而导致优先级倒置。

线程的作用域

/*
*获得/设置线程的作用域
*attr:线程属性变量
*scope:线程的作用域
*若成功返回0,若失败返回-1
*作用域控制线程是否在进程内或在系统级上竞争资源
*值为PTHREAD_SCOPE_PROCESS(缺省),此线程将与进程中的其他线程进行竞争
*值为PTHREAD_SCOPE_SYSTEM,此线程将 与系统中的所有线程进行竞争
*/
int pthread_attr_setscope(pthread_attr_t *attr,int scope);
int pthread_attr_getscope(const pthread_attr_t *attr,int *scope);

线程分离和非分离属性

/*
*设置线程属性,分离or非分离
*成功返回0,失败返回错误码
*PTHREAD_CREATE_DETACHED(分离线程)
*PTHREAD _CREATE_JOINABLE(非分离线程)
*/
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
/*
*获取程属性,分离or非分离
*成功返回0,失败返回错误码
*/
int pthread_attr_getdetachstate(pthread_attr_t *attr, int detachstate);

线程堆栈地址

/*
*获得/修改线程栈的位置
*attr:指向一个线程属性的指针
*stackaddr:栈地址
*成功返回0,若失败返回-1
*/
int pthread_attr_getstackaddr(const pthread_attr_t *attr,void **stackaddf);
int pthread_attr_setstackaddr(pthread_attr_t *attr,void *stackaddr);

线程栈地址和大小

/*
*修改或获取栈地址的函数
*attr:指向一个线程属性的指针(由pthread_attr_init函数初始化)
*stackaddr:返回获取的栈地址
*stacksize:返回获取的栈大小
*成功返回0,若失败返回-1
*/
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
int pthread_attr_getstack(pthread_attr_t *attr, void **stackaddr, size_t *stacksize);

线程栈大小

//设置stacksize属性时,选择的stacksize不能小于PTHREAD_STACK_MIN
/*
*获得/修改线程栈的大小
*attr:指向一个线程属性的指针
*stacksize:返回线程的堆栈大小
*成功返回0,若失败返回-1
*/
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize); 

线程栈保护区大小

/*
*线程属性guardsize控制着线程栈末尾之后用以避免栈溢出的扩展内存大小
*可以把guardsize线程属性设置为0,不允许属性的这一特征行为发生:在这种情况下,不会提供警戒缓冲区
*如果修改了栈地址stackaddr,系统就会默认由我们自己管理栈,进而使警戒缓冲区机制无效,等同于把guardsize置为0
*/

/*
*获得/修改线程栈末尾的警戒缓冲区大小
*attr:线程属性变量
*guardsize:缓冲区大小
*成功返回0,若失败返回-1
*如果guardsize被修改,操作系统可能会把它取为页大小的整数倍。如果线程的栈指针溢出到警戒区,应用程序就可能通过信号接收到出错信息
*成功返回0,失败返回错误码
*/
int pthread_attr_setguardsize(pthread_attr_t *attr,size_t guardsize);
int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,size_t *restrict guardsize);

线程的作用域(scope)

作用域属性描述特定线程将与哪些线程竞争资源。线程可以在两种竞争域内竞争资源:

  • 进程域(process scope):与同一进程内的其他线程
  • 系统域(system scope):与系统中的所有线程。一个具有系统域的线程将与整个系统中所有具有系统域的线程按照优先级竞争处理器资源,进行调度
  • Solaris系统,实际上,从 Solaris 9 发行版开始,系统就不再区分这两个范围

线程的绑定状态(binding state)

关于线程的绑定,牵涉到另外一个概念:轻进程(LWP:Light Weight Process):轻进程可以理解为内核线程,它位于用户层和系统层之间。系统对线程资源的分配、对线程的控制是通过轻进程来实现的,一个轻进程可以控制一个或多个线程

  • 非绑定状态
    默认状况下,启动多少轻进程、哪些轻进程来控制、哪些线程是由系统来控制的,这种状况即称为非绑定的
  • 绑定状态
    绑定状况下,即某个线程固定的"绑"在一个轻进程之上。被绑定的线程具有较高的响应速度,这是因为CPU时间片的调度是面向轻进程的,绑定的线程可以保证在需要的时候,总有一个轻进程可用。通过设置被绑定的轻进程的优先级和调度级可以使得绑定的线程满足诸如实时反应之类的要求

线程的分离状态(detached state)

  • 线程的分离状态决定一个线程以什么样的方式来终止自己
  • 非分离状态
    线程的默认属性是非分离状态,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源
  • 分离状态
    分离线程没有被其他的线程所等待,自己运行结束,线程也就终止了,马上释放系统资源
  • 线程分离状态的函数
/*
*第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)
*/
pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
  • 如果设置一个线程为分离线程,而这个线程运行又非常快,很可能在pthread_create函数返回之前就终止了,终止之后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用pthread_cond_timewait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。但是注意不要使用诸如wait()之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题

线程优先级(priority)

  • 新线程的优先级为默认为0
  • 新线程不继承父线程调度优先级(PTHREAD_EXPLICIT_SCHED)
  • 仅当调度策略为实时(即SCHED_RR或SCHED_FIFO)时才有效,并可以在运行时通过pthread_setschedparam()函数来改变,缺省为0

线程的栈地址(stack address)

  • POSIX.1定义了两个常量_POSIX_THREAD_ATTR_STACKADDR 和_POSIX_THREAD_ATTR_STACKSIZE检测系统是否支持栈属性
  • 也可以给sysconf函数传递_SC_THREAD_ATTR_STACKADDR或 _SC_THREAD_ATTR_STACKSIZE来进行检测
  • 当进程栈地址空间不够用时,指定新建线程使用由malloc分配的空间作为自己的栈空间。通过pthread_attr_setstackaddrpthread_attr_getstackaddr两个函数分别设置和获取线程的栈地址。传给pthread_attr_setstackaddr函数的地址是缓冲区的低地址(不一定是栈的开始地址,栈可能从高地址往低地址增长)

线程的栈大小(stack size)

  • 当系统中有很多线程时,可能需要减小每个线程栈的默认大小,防止进程的地址空间不够用
  • 当线程调用的函数会分配很大的局部变量或者函数调用层次很深时,可能需要增大线程栈的默认大小。
  • 函数pthread_attr_getstacksizepthread_attr_setstacksize提供设置

线程的栈保护区大小(stack guard size)

  • 在线程栈顶留出一段空间,防止栈溢出
  • 当栈指针进入这段保护区时,系统会发出错误,通常是发送信号给线程
  • 该属性默认值是PAGESIZE大小,该属性被设置时,系统会自动将该属性大小补齐为页大小的整数倍
  • 当改变栈地址属性时,栈保护区大小通常清零

线程的调度策略(schedpolicy)

POSIX标准指定了三种调度策略:先入先出策略 (SCHED_FIFO)、循环策略 (SCHED_RR) 和自定义策略 (SCHED_OTHER):

  • SCHED_FIFO 是基于队列的调度程序,对于每个优先级都会使用不同的队列
  • SCHED_RR 与 FIFO 相似,不同的是前者的每个线程都有一个执行时间配额。SCHED_FIFO 和 SCHED_RR 是对 POSIX Realtime 的扩展
  • SCHED_OTHER 是缺省的调度策略。

新线程默认使用 SCHED_OTHER 调度策略。线程一旦开始运行,直到被抢占或者直到线程阻塞或停止为止。

  • SCHED_FIFO
    如果调用进程具有有效的用户 ID 0,则争用范围为系统 (PTHREAD_SCOPE_SYSTEM) 的先入先出线程属于实时 (RT) 调度类。如果这些线程未被优先级更高的线程抢占,则会继续处理该线程,直到该线程放弃或阻塞为止。对于具有进程争用范围 (PTHREAD_SCOPE_PROCESS)) 的线程或其调用进程没有有效用户 ID 0 的线程,请使用 SCHED_FIFO,SCHED_FIFO 基于 TS 调度类。
  • SCHED_RR
    如果调用进程具有有效的用户 ID 0,则争用范围为系统 (PTHREAD_SCOPE_SYSTEM) 的循环线程属于实时 (RT) 调度类。如果这些线程未被优先级更高的线程抢占,并且这些线程没有放弃或阻塞,则在系统确定的时间段内将一直执行这些线程。对于具有进程争用范围 (PTHREAD_SCOPE_PROCESS) 的线程,请使用 SCHED_RR(基于 TS 调度类)。此外,这些线程的调用进程没有有效的用户 ID 0

线程并行级别(concurrency)

应用程序使用 pthread_setconcurrency() 通知系统其所需的并发级别

你可能感兴趣的:(Linux)