一.线程概念(也叫轻量级进程)
1.在一个程序中的一条执行路线就叫做线程,更准确的说:线程是进程的一个内部的控制序列
2.一个进程中至少有一个执行线程(控制序列)
二.线程和进程的区别
1.进程是资源分配的基本单位,也是调度运行的基本单位,是系统中并发执行的单位。
2.线程是进程中执行运算的最小单位
3.线程共享进程的所有数据(内存和资源),但它也有自己一部分独立的数据(进程ID,一组寄存器,栈,上下文,errno,信 号屏蔽字,调度优先级)
4.一个进程可以有多个线程,但一个线程只能属于一个进程
5.线程是一种轻量级的进程,与进程相比,线程给操作系统带来侧创建、维护、和管理的负担要轻,意味着线程的代价或开销比 较小。
6.线程没有地址空间,它在进程的地址空间中。线程的文本包含在进程的代码段中
7.父子进程通过进程间通信进行通信,同一个进程间的不同线程通过读写数据通信
8.同一个进程的线程处于相同的级别,线程可以对其他线程进行控制,可以销毁其他线程也可以销毁主线程,从而销毁进程
9.子进程不能对其他的子进程施加控制,线程之间可以,也可以对主线程控制。
三.同一个进程中线程的共享资源
1.同一个地址空间(进程的全局变量和函数,资源和环境)
2.文件描述符表(代码和数据)
3.每种信号的处理方式
4.当前工作目录
5.用户id和组id
四.线程的优点
1.创建销毁一个新线程的代价比创建销毁一个新进程要小得多
2.线程之间切换需要操作系统做的工作比进程之间切换要小的多
3.线程占用的资源比进程少得多
4.线程之间共享数据方便
5.能充分利用多处理器的可并行数量
6.在等待较慢的I/O操作结束的同时,其他线程还可以执行计算
7.计算密集型应用,为了能在多处理系统上运行,将计算分解到多个线程中实现
8.I/O密集型应用,为了提高性能呢,将I/O操作重叠,线程可以同时等待不同的I/O操作
五.线程的缺点
1.性能损失 2.健壮性降低 3.缺乏访问控制 4.编程难度提高,调试难度提高 5.线程终止影响进程
六.进程控制API(需要链接pthread库)
1.创建一个新线程
1)头文件: #include <pthread.h>
2)函数原型:int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
3)函数参数:第一个参数返回线程id,attr设置线程的属性(默认为NULL),第三个参数是线程启动后执行的动作(函数指 针),第四个参数是线程启动函数的参数
4)返回值:成功返回0,失败返回错误码
5)例子:
1 #include <stdio.h>
2 #include <pthread.h>
3 #include <string.h>
4
5 void arg(void){
6 while(1){
7 printf("small pthread!\n");
8 sleep(1);
9 }
10 }
11
12 int main(void){
13 pthread_t tid;
14 int ret=pthread_create(&tid,NULL,(void*)arg,NULL);
15 if(ret!=0){
16 printf("%s\n",strerror(ret));
17 return 1;
18 }
19
20 for(;;){
21 printf("main pthread!\n");
22 sleep(2);
23 }
24 return 0;
25 }
查看线程id
其中LWP是线程的id(可以通过gettid()获取),NLWP是线程组(多线程的进程)内线程的个数,可以看出以上程序中有两个线程,一个主线程,一个新创建的线程
而且,线程组的tid就是主线程的tid,主线程tid就是当前进程的pid
同一个线程组的线程,没有层次关系,所有的线程都是对等关系
2.获取当前线程id
1)头文件:#include <pthread.h>
2)函数原型:pthread_t pthread_self(void);
3)返回值:返回线程id
3.线程终止(3种方法)
a)在线程函数中return,但不适用于主线程,主线程return直接终止进程,相当于调用了exit
b)线程调用pthread_exit自杀
c)一个线程可以调用pthread_cancel终止同一个进程中的另一个线程
1)pthread_exit (自杀)
o)头文件:#include <pthread.h>
o)函数原型:void pthread_exit(void *retval);
o)参数:retval不要指向一个局部变量(得到返回指针时若在栈上就已经销毁了,应该是全局或堆上内存)
o)无返回值:线程结束无法再回到它的调用者
2)pthread_cancel(他杀)
o)头文件:#include <pthread.h>
o)函数原型:int pthread_cancel(pthread_t thread);
o)参数:要杀死的进程的id
o)返回值:成功返回0,失败返回错误码
o)此函数要求遇到取消点才执行,人为添加取消点void pthread_testcancel(void);这个函数的作用就是请求交付任何未决的取消请求
4.线程等待
1)线程等待的作用
a)已经退出的线程,其空间没有被释放,仍然在进程的地址空间中
b)创建新的线程不会复用刚才退出的线程地址空间
2)API(pthread_join)(只有阻塞方式)
a)头文件:#include <pthread.h>
b)函数原型:int pthread_join(pthread_t thread, void **retval);
c)参数:thread等待线程的id ,retval指向一个指针,指向了线程的返回值
d)返回值:成功返回0,失败返回错误码
e)线程退出情况不同retval指向的单元存放的数据也不同(任何线程都可等待其他线程)
1>return返回,单元中存放线程函数的返回值
2>pthread_cancel异常终止,单元中存放常数PTHREAD_CANCELED(-1)
3>pthread_exit终止,存放传给pthread_exit的参数
4>对线程终止不感兴趣,写NULL
5.线程分离 (线程在终止时由系统自动释放资源,不能被其他线程回收或者杀死)
1)线程分离的作用
a)默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join的操作,否则无法释放资源,会造成内存泄漏
b)如果不关心线程的返回值,join就多此一举了,这个时候可以告诉系统,当线程退出时,自动释放资源
2)API
1>头文件:#include <pthread.h>
2>函数原型:int pthread_detach(pthread_t thread);
3>参数:要分离的线程id (可以分离自己,也可以分离其他线程)
4>join与detach冲突
具体用例,请看之后博客--线程池