IPC——线程

进程缺点

为了让每个进程有一个安全的独立进程空间,OS使用了虚拟内存机制,通过虚拟内存机制,能够让每一个进程都有完全独立的进程空间。这种独立的进程空间最大的优点就是,可以很好地保证每一个进程的安全,不被其它进程所攻击或者干扰,但是突出的优点往往又会导致另外的缺点。拥有独立进程空间的进程有两大明显的缺点:

①进程间切换的计算机资源开销很大,切换效率非常低

OS是通过虚拟内存机制来实现进程空间独立的,进程在并发运行时需要相互间的切换,切换时必然需要涉及虚拟内存机制的控制,但是虚拟内存机制比较复杂,所以在进行进程间切换时,会耗费高昂的cpu、缓存(cache)、内存等计算机资源,也非常耗费切换时间。

②进程间数据共享的开销也很大

当程序涉及多进程时,往往会涉及到进程间的通信,但是由于进程空间的独立性,OS提供了各种各样的通信机制,这些通信机制共同原理就是,通过OS来转发进程间的数据,但是调用OS提供的这些通信机制的函数时,这些OS函数的运行也是需要消耗相当cpu、内存等计算机资源的,同时也很耗费时间。因此,对于我们有OS的计算机来说,虽然进程是必不可少的,但是进程确又不能太多,进程太多会导致计算机资源被剧烈消耗,此时你会发现你的计算机非常的卡。

早期应用进程主要目的

①创建子进程,执行新程序

②创建子进程得到多进程,通过多进程并发实现多线任务

例如:同时阻塞的读鼠标和键盘时,如果单线的话会想互影响,需要两线任务来实现。读写管道时,读操作是阻塞的,为了避免读操作影响写操作,也需要两线任务同时进行。

对于第一种目的,执行新程序时必须创建子进程,这个无法逃避的。但是对于第二种目的来说,如果使用多进程来实现就存在巨大的问题,因为几乎所有的程序都涉及多线任务的操作,而且好些程序往往都是十几个任务以上,如果此时使用多进程来实现多线任务的,这就大致大量进程的产生。比如计算机运行了100个程序,假设每个程序平均10多个任务,如果全部采用多进程来实现,计算机最终要运行的进程就多达上1000个。所以在早期使用多进程来实现程序的多线任务时,往往导致计算机进程数量暴增,而进程切换和进程间通信的计算机资源开销又很大,因此往往导致计算机非常卡顿,程序的运行效率非常低。

引入线程

线程弥补了进程再多线并发上的不足。首先我们需要明白,线程与进程一样,线程和进程会被OS统一调度,所以所有的线程和进程都是一起并发运行的,如果线程不是并发的,是不可能实现程序的多线任务的。有了线程以后,凡是程序涉及到多线任务时,都使用多线程来实现,使用多线程来实现时,线程间的切换和数据通信的开销非常低,正因为开销非常低,因此线程还有另一个名称,叫“轻量级的进程”。

线程间数据通信开销很低

线程的本质就是函数,函数间通信(数据共享)有两种方式:

①具有相互调用关系函数来说

使用函数传参来通信。

②对于没有调用关系的函数来说

使用全局变量来通信。A函数 ————> 全局变量 ————> B函数

所以说全局变量的作用是什么?就是用来实现无调用关系的函数间通信的。

进程中所有的线程函数除了相互并发运行外,没有调用关系,所以线程函数间想要数据共享的话,就使用全局变量来通信。

从这里可以看出,进程内部的线程间进行数据共享非常容易,使用全局变量即可,根本不需要调用什么OS提供的通信机制,所以线程间通信的开销自然就非常的低。

线程之间切换开销很低

使用多线程来实现多线任务时,由于线程本质上它只是程序(进程)的一个函数,只不过线程函数与普通函数的区别是,普通函数是单线的运行关系,而线程函数被注册为线程后,是多线并发运行。对于普通函数来说,只有当相互调动时才会涉及函数间的切换,但是对于线程函数来说,只要运行的时间片到了就会切换,但是不管是那种函数间的切换,进程自己函数的切换只是进程内部的事情,不涉及进程间切换,就省去了进程间切换的巨大开销。

如果是不同进程的线程之间需要切换的话,还是会涉及到进程间的切换了,但是不管怎们说,线程的出现,至少为程序内部多线任务之间的切换,省去了大笔的进程切换所导致“资源开销”。

线程的切换其实就是函数间的切换,函数切换当然也需要开销,但是这些开销相比进程间切换的开销来说,已经非常小了。

可否只要线程不要进程

不可以。

线程是不可能完全替代掉进程的,只有在多线任务时会替代进程,但是运行新程序的时,我们还是必须创建子进程。线程的本质是函数,函数运行需要内存空间,这个内存空间怎么来,事实上线程运行的内存空间就是进程的内存空间,因此线程运行时必须依赖于进程的存在,如果没有进程所提供的内存空间这个资源,线程根本无法运行。换句话说,线程作为函数,只是进程的一个部分而已,线程是不可能脱离进程而独立存在。所以同一个进程中的所有线程,都是运行在相同的进程空间中的,换句话说同一个进程中所有线程共相同的进程空间。

参考:剖析可执行文件ELF组成 可执行文件内存布局

线程自己独立的属性

进程中的所有线程会共享进程提供资源(全局变量、工作目录、打开的文件描述符、子函数等等),但是每个线程作为一个单独的执行体,也有属于自己的独立的东西。

每个线程拥有自己独立的线程ID(TID)

每个线程有独立的切换状态

1)在切换时,当前线程被中断的那条指令的地址

2)线程切换时相关的运行状态

当线程切换时,必须保存以上信息,以便切换回来后还原现场,从中断处继续运行。

有自己独立的函数栈

其实每一个函数都有自己的函数栈,所有的函数栈都开辟于进程空间的进程栈。函数栈的作用就是用来保存函数局部变量的,既然所有的线程函数都有自己的独立的函数栈,自然就有自己独立的局部变量。线程函数的函数栈,我们往往也称为线程栈。

自己独立的错误号

线程函数的错误号是独立的,所以线程函数出错时,错误号并不是通过设置errno实现的,而是直接将错误号返回。

每一个线程有自己独立的信号屏蔽字和未决信号集  参考:IPC——信号

每个线程有自己独立的tack_struct结构体

进程在运行的过程中,OS会为每个进程开辟一个task_struct结构体变量用于存放进程所涉及到的各种管理信息,同样的为了管理线程,也会为线程开辟一个task_struct变量,只不过适用于存放线程的管理信息的。

API

实现多进程的时候有进程控制,进程控制涉及到的函数有fork、exec、wait、exit等函数,实现多线程的时候同样有线程控制函数,这些线程控制函数有:pthread_create、pthread_join、 pthread_detach、pthread_cancel、pthread_exit等。

进程控制的fork、exec等函数都是由os系统提供,但是线程控制函数却不是有os提供。原本线程函数也可以完全由OS来实现,但是后来为了不给OS增加负担,同时也为了提高线程的灵活性,后来的线程就不再由OS提供,而是由单独的线程库来提供,不过线程库在实现时,也是调用了相应的系统API的,也就是说线程的核心实现也是离不开OS支持的。

如果man手册查不到线程库函数,可以在线安装

sudo apt-get install glibc-doc :安装线程库
sudo apt-get install manpages-posix-dev:安装线程库的函数手册
View Code

pthread_create

原型

#include <pthread.h>
                    
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
View Code

功能

把void *(*start_routine) (void *)函数注册为一个线程函数,该函数一旦注册成功,这个函数就以次线程的方式开始并发运行起来,如果不注册的话,这个函数就是一个普通函数。凡是使用pthread_create注册的线程,都是次线程,次线程会和主线程一起并发运行。

谁是主线程?

main函数的那条线就是主线程,如果一个次线程都没有创建的话,整个进程就只有一个主线程,这个主线程也是整个进程。

参数

thread:存放线程的TID。

attr:用于设置线程属性,设置线程属性的目的是为了实现某些特殊功能,如果设置为NULL,表示不设置特有的属性,使用线程默认属性所提供的功能即可。正常情况下,线程默认属性所提供的功能就已经够用了,所以这个参数我们都是设置为NULL。

start_routine:要注册为线程的函数地址

函数类型为void *(*) (void *),pthread_create它会把这个函数注册为线程,如果不注册,线程函数就是一个普通的函数。

线程函数需要我们自己定义,比如:

void *pth_fun(void *pth_arg)
{
    ...//线程要做的事情
}
View Code

pth_fun和pth_arg的命名由自己决定。

arg:传递给线程函数的参数,这个参数会传递给pth_arg,如果参数很多的话,我们做成一个结构体,然后把结构体变量的地址传过去。如果你不想传递参数的话,你可以设置为NULL。

返回值

成功返回0,失败返回非零错误号。

pthread_cancel

原型

功能

参数

返回值

pthread_exit

原型

功能

参数

返回值

pthread_self

原型

功能

参数

返回值

pthread_join

原型

功能

参数

返回值

pthread_detach

原型

功能

参数

返回值

猜你喜欢

转载自www.cnblogs.com/kelamoyujuzhen/p/9435386.html
IPC