线程是独立调度的基本单位。一个进程可以有一个或者多个线程,线程之间共享进程资源。
按调度者分为:
用户级线程(User Level Thread,ULT)
解决上下文切换问题,调度算法和过程由用户决定
存在于用户空间
线程创建、撤销以及线程之间的同步、通信无需系统调用来实现
同一进程的线程切换不需要内核支持
调度以进程为单位
优点:
线程切换不需要到内核空间,节省内核空间
调度算法可以进程专用,亦或用户程序指定
用户线程实现与操作系统无关
缺点:
同一进程一个线程执行系统调用阻塞就导致进程阻塞
一个进程只能在一个CPU上获得执行,无法发挥SMP(对称多处理器)的优势
核心级线程(kernel Supported threads,KST)
不同进程的线程按照同一相对优先调度算法调度,发挥SMP优势
线程创建撤销、以及切换等等通过系统调用陷入内核由内核响应程序处理
调度以线程为基本单位
优点:
在SMP情况下,内核可以调度同一进程通中的多个线程并发工作
同一线程的一个线程阻塞,其他线程依然可以运行
缺点:
主要是程序在内核态和用户态之间切换带来的开销
线程的创建:
pthread_create - create a new thread //创建一个新线程
//头文件
#include
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
thread —— 新线程TID(Thread id 类似进程的pid)
attr —— 线程属性,为NULL创建一个标准线程
start_routine —— 线程入口函数
arg —— 线程入口参数
RETURN VALUE
成功返回0; 错误返回errno, and the contents of *thread are undefined.
errno
—— 一个全局变量,存放各种API执行失败的原因
pthread_exit()
pthread_cancel
取消线程exit()
或者main线程
调用了return
,都将导致所有线程退出pthread_exit - terminate calling thread
#include
void pthread_exit(void *retval); //线程退出
retval —— 退出值
Compile and link with -pthread.//编译要链接pthread库
pthread_cancel - send a cancellation request to a thread //发送取消线程请求
#include
int pthread_cancel(pthread_t thread); //取消线程
RETURN VALUE
成功 pthread_cancel() 返回 0; 失败, 返回非零 error number.
pthread_join - join with a terminated thread
#include
int pthread_join(pthread_t thread, void **retval); //获取线程退出值
thread —— 线程TID
retval —— 线程退出值
RETURN VALUE
成功 pthread_join() 0; 失败返回 error number.
pthread_self - obtain ID of the calling thread
#include
pthread_t pthread_self(void);
RETURN VALUE
成功返回线程TID,不存在失败
创建标准线程:
/***************************************************************************************************
* @file: xxx.c
* @author: guangjieMVP
* @github:
* @version: v1.0.0
* @date: 2020-xx-xx
* @brief:
*****************************************************************************************************/
#include
#include
#include
#include
#include
int retval = 0xff;
void *thread1_entry(void *arg)
{
static int cnt = 0;
while (1)
{
printf("Linux %d\r\n", cnt++);
if(cnt >= 10)
{
cnt = 0;
pthread_exit(&retval);
}
sleep(2);
}
}
void *thread2_entry(void *arg)
{
while (1)
{
printf("ubuntu\r\n");
sleep(3);
}
}
int main(int argc, char **argv)
{
pthread_t thread1;
pthread_t thread2;
pthread_create(&thread1, NULL, thread1_entry, NULL); //attr为NULL——使用默认属性创建thread
pthread_create(&thread2, NULL, thread2_entry, NULL);
static int maincnt = 0;
unsigned char flag = 0;
while(1)
{
printf("main thread %d\r\n", maincnt++);
if(maincnt >= 10 && !flag)
{
maincnt = 0;
flag = 1;
pthread_cancel(thread2);
}
sleep(1);
}
return 0;
}
编译执行:
gcc pthread_create.c -o pthread_create -lpthread //编译程序
//-lpthread —— 链接pthread线程库
./pthread_create //执行程序
默认情况下线程是可连接状态——线程退出时不会释放资源,其他线程可以通过pthread_join()
获取其退出值
不关心线程返回状态可以把线程设置为可分离的——线程结束系统自动释放并清理资源,线程必定不会成为僵尸线程
s
pthread_detach - detach a thread //设置线程属性为分离
#include
int pthread_detach(pthread_t thread);
thread —— 线程ID
RETURN VALUE
成功返回0; 失败, 返回errno
线程属性包含属性:线程栈的大小和位置、调度策略、优先级等以及线程是分离还是可连接
pthread_attr_init, pthread_attr_destroy - initialize and destroy thread attributes object //初始化或者销毁销毁线程属性
头文件
#include
int pthread_attr_init(pthread_attr_t *attr); //初始化线程属性
int pthread_attr_destroy(pthread_attr_t *attr);//销毁线程属性
attr —— 线程属性
pthread_attr_setdetachstate, pthread_attr_getdetach‐state - 设置or获取线程的分离状态
#include
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
attr —— 线程属性
detachstate —— 分离状态:
PTHREAD_CREATE_DETACHED — 分离状态
PTHREAD_CREATE_JOINABLE — 可连接状态
RETURN VALUE
成功返回0; 失败返回非0的errno
int ret;
pthread_attr_t attr; //定义线程属性变量
ret = pthread_attr_init(&attr); //初始化线程属性变量
if(ret != 0)
{
printf("faild to init attr\r\n");
exit(0);
}
ret = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);//设置线程为分离状态
if(ret != 0)
{
printf("faild to setdetach\r\n");
exit(0);
}
pthread_create(&thread1, &attr, thread1_entry, NULL); //使用attr属性创建线程
pthread_create(&thread2, &attr, thread2_entry, NULL);
pthread_attr_setschedpolicy, pthread_attr_getschedpolicy - 获取or设置线程调度策略
#include
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); //设置线程调度策略
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
attr —— 线程属性
policy —— 调度策略
SCHED_FIFO —— 以先进先出的派对方式调度,处于就绪就会被立即放入所在优先级队列队尾
被更高优先级抢占后会被放入所在优先级队列队头,高优先级运行结束其立即
恢复运行
可以调用sched_yield()主动让出CPU
SCHED_RR —— 以轮转的方式调度, 线程会被分配一定的时间片,
时间片耗尽会被放入所在优先级队列的队尾
SCHED_OTHER —— 非实时调度的普通线程,静态优先级必须设置为0,使用Linux系统默认的调度策略——按照动态优先级调度
RETURN VALUE
On success, these functions return 0; on error, they return a nonzero error number.
pthread_attr_setschedparam, pthread_attr_getschedparam - 设置、获取静态线程优先级
#include
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
//attr —— 线程属性
//param —— 线程静态优先级
RETURN VALUE
On success, these functions return 0; on error, they return a nonzero error number.
pthread_setschedparam, pthread_getschedparam - 设置or获取线程调度策略以及静态优先级
#include
int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param); //设置调度策略以及静态优先级
int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param);
//thread —— 线程TID
//policy —— 调度策略
//param —— 静态优先级
struct sched_param {
int sched_priority; /* Scheduling priority */
};
nice - change process priority
#include
int nice(int inc);
线程创建后都有一个线程栈,缺省情况下大小固定。线程栈大小可以改变
#include
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
attr —— 线程属性结构体
stackaddr —— 线程栈地址
stacksize —— 线程栈大小
RETURN VALUE
成功返回0;失败返回非零错误编码