多线程编程

一、什么是线程???
线程是在进程内部运行的控制流程。多线程的控制流程可以长期共存,操作系统会在各线程之间调度和切换,就像在多个进程之间调度和切换一样。
由于同一个进程的多个线程共享同一地址空间地址空间,因此代码段和数据段都是共享的,如果定义一个函数,在各线程之中都可以调用,如果定义一个全局变量,在各线程中都可以访问到的,除此之外,线程还共享以下资源:
1、文件描述符表
2、每种信号的处理方式
3、当前工作目录
4、用户id和组id
5、堆空间
但是有些资源是每个线程各有一份的
1、线程id
2、上下文,包括各种寄存器的值、程序计数器和栈指针
3、栈空间
4、errno变量
5、信号屏蔽字
6、调度优先级
二、线程的原理
下面所介绍的是Linux中线程的原理。回想一下我们所说的线程的概念,线程是一个控制流程,那么一个单执行流的进程是不是一个控制流程呢???答案是肯定的,一个单执行流的进程也是一个线程。严格来说linux中是没有线程的概念的,linux中的线程都是用进程模拟的,所以linux中的线程又叫做轻量级进程。
我们知道,进程是操作系统分配资源的最小单位,每当内核中新创建一个PCB的时候,就表示内核中新创建了一个进程。如下图,内核会为新创建的进程分配一系列的数据结构用来管理进程。
这里写图片描述
在linux中可以通过vfork()函数来创建一个子进程,在vfork分流之后、如果子进程中没有使用exec函数进行程序替换的话,则子进程会在父进程的地址空间中运行父进程的代码。
这时候PCB1和PCB就拥有相同的虚拟内存和相同的物理内存了,如果我们这时候再为PCB1创建一些他私有的资源(比如为他分配栈空间,给他独立出来一部分页表),那么PCB1就变成一个线程了。
三、线程的使用
下面所介绍的函数都是POSIX标准制定的,所有函数都在线程共享库中,所以在使用的时候要引入头文件pthread.h。

1、线程的创建
int pthread_create(pthread_t tid,const pthread_attr_t *attr,void (start_routine)(void),void *arg);

返回值:成功返回0,失败返回错误码。可以通过char *strerror(int errnum)函数提取错误信息。
tid:用来保存线程的id。属于一个输出型参数,将线程的id保存起来。
attr:用来修改线程的属性。如果为NULL的时候表示创建的线程是默认属性。
start_routine:start_routine是一个函数指针,它指向一个返回值为void*,参数为void* 函数。该线程创建好了以后就会执行这个函数。当start_routine返回之后该线程就退出了。
arg:是start_routine所指向函数的参数。

2、线程的终止
线程的终止有三种方式:
return
使用return可以终止一个线程,但是如果是在main函数中调用return的话,相当于进程退出,那么所有线程都会退出,相当于调用exit或_exit函数。在任意一个线程中调用exit或_exit的话会使所有线程退出。

void pthread_exit(void *retval)
在线程中调用pthread_exit()可以使线程自己退出。退出的信息可以通过参数传出去,被等待他的线程获取。
int pthread_cancel(pthread_t tid)
在一个线程中调用pthread_cancel函数可以终止另一个线程。假设A线程是被pthread_cancel异常终止的,则pthread_join获取的线程A的退出码就是PTHREAD_CANCEL,这个宏的值是-1,可在pthread.h头文件中找到。
返回值:成功返回0,失败返回错误码。
tid:要终止的线程的id。
3、线程等待
int pthread_join(pthread_t tid,void** retval);
功能:用来等待线程退出,并回收该线程的退出信息以及释放该进程的资源。
4、获取线程的id
pthread_t pthread_self();
在一个线程中调用这个函数会返回该线程的id。

四、线程的可结合和可分离
在任何一个时间点上,线程是可结合的或是可分离的。
可结合:
一个可结合的线程能够被其他线程回收资源和杀死。在被其他线程回收之前,它的存储资源是不释放的。
可分离:
一个可分离的线程是不能被其他线程回收或杀死的,它的存储器资源在他终止的时候由系统自动释放。一个可分离的线程是不能被等待的。
int pthread_detach(pthread_t tid):
这个函数可以将一个线程设置成可分离的。一个线程可以自己调用pthread_detach(pthread_self())将自己设置为可分离的。也可以通过别的线程将自己设置为可分离的。

默认情况下,线程被创建成可结合的。如果一个可结合的线程运行结束但没有被join,则它的状态类似于僵尸进程。也就是还有一部分资源没有被回收。 为了避免存储器泄漏,每一个可结合的线程都要么被显示地回收。即调用pthread_join等待进程运行结束,并可得到线程的退出码,回收其资源。或者是调用pthread_detach函数将线程分离。在调用pthread_join之后,如果该线程没有运行结束,则调用者会被阻塞。
当主线程退出后,就相当于进程退出了,这时候不管是可结合还是可分离的进程都会被回收结束掉。

五、线程的基本特点
1、进程是系统分配资源的基本单位,而线程是执行的基本单位。
2、线程在他在进程的内部运行,在linux中轻量级进程有可能就是线程。
3、由于进程之间代码段可数据段是共享的,所以线程间通信是很容易的。
4、由于线程是在一个进程内部运行的,所以线程的pid和组id是相同的,但是线程的id是不同的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值