linux多线程编程
- 进程与线程之前的区别
- 进程
- 线程
- 线程的特点
- 线程共享资源
- 一个进程中多个线程可以共享一下资源
- 每个线程私有的资源包括
- linux线程编程
- pthread 线程库中提供了如下基本操作
- 线程示例
- 同步和互斥机制
- 线程间通讯
- 同步
- 信号量(灯)
- 信号量-P/V操作
- 信号量的种类
- pthread库常用的信号量操作函数
- 线程同步-示例1
- 参考资料
进程与线程之前的区别
进程
- 在linux中,资源的分配是以进程为单位的;
- 进程有独立的地址空间;
- linux为每个进程创建task_struct;
- 每个进程都参与内核调度,互不影响;
线程
- 进程在切换时开销比较大
- 很多操作系统引入了轻量级进程LWP(也就是线程)
- 同一进程中的线程共享相同的地址空间
线程的特点
- 共享相同的地址空间;
- 使用多线程的好处:大大提高了任务切换的效率;避免额外的TLB&cache的刷新;
线程共享资源
一个进程中多个线程可以共享一下资源
- 可执行的指令;
- 静态数据
- 进程中打开文件描述符;
- 当前工作目录;
- 用户ID;
- 用户组ID;
每个线程私有的资源包括
- 线程ID(TID);
- PC(程序包计数器)和相关寄存器;
- 堆栈;
- 错误号;
- 优先级;
- 执行状态和属性;
linux线程编程
pthread 线程库中提供了如下基本操作
- 创建线程
#include <pthread.h>
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,
void *(*routine)(void *),void *arg);
//成功返回0,失败返回错误代码
//thread线程对象
//attr线程属性,NULL代表默认属性
//routine线程执行的函数
//arc传递给routine的参数
- 回收线程
#include <pthread.h>
int pthread_join(pthread_t thread,void **retval);
//成返回0,失败返回错误代码
//thread要回收的线程对象
//调用线程阻塞知道thread结束
//*retval接收线程thread的返回值
- 结束线程
#include <pthread.h>
void pthread_exit(void *retval);
//结束当前线程
//retval可被其他线程通过pthread_join获取
//线程私有资源被释放
线程示例
char message[32]="hello world";
void *thread_func(void *arg);
int main(int argc,char *argv[])//主线程
{
pthread_t a_thread;
void *result;
if(pthread_create(&a_thread,NULL,thread_func,NULL) != 0){
printf("fail to pthread_create\n");
exit(-1);
}
pthread_join(&a_thread,&result);
printf("result is %s\n",result);
printf("message is %s\n",message);
return 0;
}
void *thread_func(void *arg){//子线程
sleep(1);
strcpy(message,"marked by thread");
pthread_exit("thank you for waiting for me");
}
同步和互斥机制
- 信号量
- 互斥锁
线程间通讯
线程共享同一进程的地址空间
优点:线程间通讯很容易,通过全局变量交换数据
缺点多个线程访问共享数据需要同步或者互斥机制
同步
概念:同步是指对个任务按照约定的先后次序,相互配合完成一件事。
基于信号量的概念提出的一种同步机制。由信号量来决定线程是继续运行还是阻塞等待
信号量(灯)
- 信号量代表某一类资源,,其值表示系统中该资源的数量;
- 信号量是受保护的,只有通过初始化、P操作(申请资源)、V操作(释放资源);
信号量-P/V操作
P(S)含义:
if(信号量的值大于0){
申请资源;
信号量的值减1;
}else{
申请资源的任务阻塞等待;
}
V(S)含义:
信号量值加1;
if(有任务在等待资源){
唤醒等待的任务,继续运行;
}
信号量的种类
- 无名信号量(基于内存的信号量)
- 有名信号量
pthread库常用的信号量操作函数
- sem_init
#include <semaphore.h>
int sem_init(sem_t *sem,int pshared,unsigned int value);
//成功时放回0,失败返回EOF
//sem指向要初始化的信号量对象
//pshare 0:线程间 1:进程间
//信号初值
- P/V操作
#include <semaphore.h>
int sem_wait(sem_t *sem);//P操作
int sem_post(sem_t *sem);//V操作
//成时返回0,失败返回EOF
//指向要操作的信号量对象
线程同步-示例1
两个线程同步读写缓冲区(生成者/消费者问题)
char buf[32];
sem_t sem;//信号量对象
void *function(void *arc);
int main(int argc,char *argv[]){
pthread_t a_thread;
if(sem_init(sem,0,0) < 0){
perror("sem_init");
exit(-1);
}
if(pthread_create(&a_thread,NULL,function,NULL) != 0){
printf("fail pthread_create");
exit(-1);
}
}
参考资料
链接: https://www.bilibili.com/video/BV1Fs411M7d5?share_source=copy_web.