目录
一、线程
线程就是轻量级的进程,也是用来实现多任务的
是进程中的执行序列
进程---资源分配的基本单位
线程---调度执行的基本单位
线程的组成部分
私有资源:线程id、程序计数器、一组相关寄存器、栈
公共资源:多个线程共享的进程资源
二、线程的创建
线程由某个进程创建,从属于某个进程
内存:由某个进程分配独立的栈区空间(默认8M)
与其他线程和所在的进程公用数据区、堆区、文本区
内核中存储线程控制块

三、进程VS线程
1.
进程--->程序的一次执行过程,CPU资源分配的最小单位
线程--->轻量级的进程,是进程中的执行单元,CPU调度的最小单位
2.资源消耗
进程资源消耗大,每次需要0-4G的虚拟内存空间
线程只需要所在进程分配8M的栈区空间
3.效率角度
线程的创建效率比进程高
线程任务切换的效率高
多线程只需在同一进程空间内切换;多进程需要在不同的空间中切换
4.安全角度:多进程>多线程
各个进程之间空间独立,一个进程异常不会影响其余进程空间;一个线程异常结束会导致进程异常结束,进程异常结束,该进程内所有线程任务均无法向下执行
6.通信角度
线程间通信方便,进程间不能直接共享
线程共享全局变量,可以通过全局变量实现数据通信;进程空间是独立的,没有共享空间,通信实现比较复杂
四、线程调度
宏观并行,微观串行
五、线程的消亡
1.线程回收
2.线程资源回收
六、线程的函数接口
1.线程的创建
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
参数:
thread:存放线程tid空间首地址
attr:线程属性空间首地址NULL:按照线程的默认属性去创建
start_routine:回调函数线程要执行的函数的入口
arg:给线程回调函数的参数返回值:
成功:0
失败:错误码errno//判断出错 if(ret != 0) { erron = ret; perror("create fail"); return -1; }
获得线程的tid
pthread_t pthread_self(void);
线程的退出
void pthread_exit(void *retval);
retval:线程退出的遗言
可以是数字,字符串
线程空间的回收
int pthread_join(pthread_t thread, void **retval);
利用retval传给主线程遗言,传数字时,用局部变量无效
void * do_something(void *arg)
{
static int status = 99;//局部变量在函数结束后会被销毁,
printf("--%s---\n", __FUNCTION__);
pthread_exit(&status);
//pthread_exit("hello");//字符串在字符串常量区,全局有效
//return "hello";
}
//在main函数中打印状态值
main
{
···
void *retval;
pthread_join(tid, &retval);
// printf("retval = %d\n", *(int *)retval);
printf("%s\n", (char *)retval);
}
2.线程分离
int pthread_detach(pthread_t thread);
功能:将线程设置成分离属性,系统自动回收该线程
创建线程后就早点设置,防止线程都跑完了,还没设置
七、函数指针数组
1.函数指针
一个指向函数的指针
2.函数指针的定义
函数:void fun(int a,int b);
函数指针:void (*pfun)(int a,int b);
3.函数指针的赋值
初始化:void (*pfun)(int a,int b) = fun; //int *p = &a;
赋值:void (*pfun)(int a,int b);
pfun = fun; //int *p; p = &a;
4.函数指针数组
把多个函数的地址存储再一个数组中
定义指针数组:char *arg[5];
函数指针数组:void (*arg[3])(int a,int b) = {fun1,fun2,fun3};
还可以通过typedef重命名函数指针类型:
typedef void(* pfun_array)(int a,int b);
将函数指针类型重命名为pfun_array
pfun_array arg[3] = {fun1,fun2,fun3};
5.指针函数
返回指针的函数
互斥锁
多个线程访问临界资源时,存在资源竞争,造成数据错乱.
临界资源(全局变量,共享内存):多个线程可以同时操作的资源空间.
解决办法:多个线程访问临界资源时,进行排他性访问(同一时刻只允许一个线程对该临界资源进行访问)
功能:解决多线程访问临界资源时,存在资源竞争
如果只有一把锁,多个线程会竞争,谁抢到锁谁就先用
创建锁
pthread_mutex_t mutex;
初始化锁
/*
restrict mutex锁对象的地址
restrict attr锁的属性,一般传NULL
*/
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
上锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
线程控制
异步:多任务各自执行各自的任务,互相之间没有直接干扰
同步:多个任务中的某些任务按照先后顺序执行
线程间同步:多个线程在某个任务执行过程中具有先后顺序
信号量
实现线程间同步(使用同步资源访问临界资源,可以达到互斥的效果)

定义信号量对象
sem_t sem;
初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
/*****
参数:
sem:信号量对象地址
pshared: 0线程间使用
非0进程间使用
value:初始化的资源数
返回值:成功0
失败-1
*****/
申请信号量:P操作
int sem_wait(sem_t *sem);
/*
当申请的信号量资源数>0,sem_wait解除阻塞,表示申请到了该信号量,信号量资源数-1
当申请的信号量资源数=0,sem_wait阻塞等待信号量的释放
*/
释放信号量:V操作
int sem_post(sem_t *sem);
/*
该信号量的资源数自动+1
*/
销毁信号量
int sem_destroy(sem_t *sem);
信号的操作---主要就是来实现线程间的顺序
七、线程属性
对于创建线程的进程,无合适机会回收线程资源时,可以将线程设置成具有分离属性的线程。
线程属性:
线程的分离属性:线程结束时,不需要其他线程回收,会被操作系统自动回收。(类似孤儿进程)
线程的非分离属性:可以被其他线程回收(pthread_join)或结束。(僵尸进程)
设置线程的分离属性:
1.定义线程属性对象 pthread_attr_t attr;
2.初始化线程属性对象
int pthread_attr_init(pthread_attr_t *attr);//用于初始化线程对象3.设置线程的分离属性
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);参数:
detachstate是int型的宏,设置线程的属性
4.以分离属性创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);5.销毁线程属性对象
int pthread_attr_destroy(pthread_attr_t *attr);
设置分离属性线程示例
pthread_t tid;//定义线程tid
pthread_attr_t attr;//定义线程属性对象
pthread_attr_init(&attr);//初始化线程属性对象
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//设置分离属性
pthread_create(&tid, &attr, task, NULL);//以分离属性创建线程
用非分离属性创建线程,系统资源不断被申请,却没有主动回收

用分离属性创建线程,线程执行结束后,就会被操作系统回收,重复利用空间

八、线程间通信
使用全局变量进行数据共享,临界资源容易导致资源竞争



2922

被折叠的 条评论
为什么被折叠?



