Linux中多进程(多线程)编程

来源:互联网 发布:ubuntu下的下载工具 编辑:程序博客网 时间:2024/04/30 12:47
多进程编程
一、复制进程映像的fork系统调用
1)

父进程返回子进程的PID,子进程返回0
2)写时拷贝
子进程与父进程代码完全一致,同时它还会复制父进程的数据(堆数据,栈数据及静态数据),采用写时拷贝技术,只有在任一进程对数据进行了读写操作时,拷贝才会发生。

 二、exec 系列系统调用
  在子进程中执行其他程序,即替换当前进程映像                                                                                                                                                                                                                                                                                                                                                                                                  
1) 系统调用exec是以新的进程去代替原来的进程,但进程的PID保持不变。
因此,可以这样认为,exec系统调用并没有创建新的进程,只是替换了原来进程上下文的内容。原进程的代码段,数据段,堆栈段被新的进程所代替。

一个进程主要包括以下几个方面的内容:
(1)一个可以执行的程序
(2) 与进程相关联的全部数据(包括变量,内存,缓冲区)
(3)程序上下文(程序计数器PC,保存程序执行的位置)
 
exec 是一个函数簇,由6个函数组成,分别是以excl和execv打头的。具体如下:
execl (const char* filepath,const char* arg1,char*arg2......)
execlp (const char*filename,const char*arg1,const char*arg2..... )
execle (const char*filepath,const char*arg1,const char*arg2,.....,char* cons envp[])
execv  (const char* filepath,char* argv[])
execvp (const char* filename,char* argv[])
execve (const char* filepath,char*argv[],char* const envp[])
path参数制定可执行文件的完整路径,file参数可以接收文件名,envp参数用于设置新程序的环境变量,只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。
一般情况下,exec函数是不返回的,出错返回-1.若没有出错,则原程序中exec调用之后的代码都不会执行 ,因为此时源程序已经被exec的参数制定的程序完全替代
exec函数不会关闭源程序打开的文件描述符的
三、处理僵尸进程
见关于进程的笔记

多线程编程(Linux下)  <pthread.h>
一、线程模型
线程是程序中完成一个独立任务的完整执行序列,是一个可调度的实体
内核线程,运行在内核空间,油内核来调度;用户线程运行在用户空间,由线程库来调度;内核线程相当于用核线程运行的的容器。
一个进程可以包含M个内核线程和N个用户线程,M<=N
线程的实现分为:
完全在用户空间实现:优点:无需内核干涉不占用额外的内核资源;缺点:对于多处理器系统,一个进程的多个线程无法运行在不同的CPU上
完全由内核调度      双层调度(充分利用多次处理器的优势)
二、创建线程和结束线程
1、创建线程:
int  pthread_create(pthread_t*  thread, const  pthread_attr_t* arr,  void* (*start_routine)(void*), void  arg);
2、退出线程:void   pthread_exit(void *retval);
3、回收其他线程:int  pthread_join(pthread_t  thread, void **retval);
一直阻塞直到被回收的线程结束为止
4、取消该线程:int  pthread_cancel(pthread_t  thread);  //成功返回0
三、用于线程同步的机制:POSIX信号量    互斥量   条件变量
1、信号量

2、互斥锁
1)

pthread_mutex_lock:加锁操作,如果目标锁已被锁上,将会阻塞,直到解锁
pthread_mutex_unlock:解锁操作,如果此时有其他线程正在等待这个互斥锁,则这些线程中的某一个将会获得它
pthread_mutexattr_t  结构体定义了一整套完整的互斥锁属性
互斥锁的两种常用属性:pshared(指定是否允许跨进程共享互斥锁)  
type(制定互斥锁的类型:普通锁、检错锁、嵌套锁、默认锁)
2)死锁:指两个或者两个以上的进程在执行过程中,因为争夺资源而造成的一中互相等待的现象,若无外力作用,他们都将无法推进下去
产生死锁的原因:
1)因为系统资源不足
2)进程运行推进的顺序不合适
3)资源分配不当等
产生死锁的必要条件:
1)互斥条件:一个资源每次只能被一个进程使用
2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
3)不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源
死锁的处理方法:
1)预防死锁:破坏产生死锁的四个必要条件众多的一个或几个,可能会导致系统资源利用率和吞吐量降低
2)避免死锁:在资源的动态分配过程中,用某种方法去防止系统进入不安全状态
3)检测死锁:此方法允许系统在运行过程中发生死锁。但可通过系统所设置的检测机构,及时地检测出死锁的发生,并精确地确定与死锁有关的进程和资源,然后采取适当措施,从系统中将已发生的死锁清除掉。
4)解除死锁 :撤销或挂起一些进程,以便回收一些资源,再将这些资源分配给已处于阻塞状态的进程,使之转为就绪状态,以继续运行。
死锁:1)在一个线程中对一个已经加锁的普通锁再次加锁
          2)两个线程按照不同的顺序来申请两个互斥锁
3、条件变量:用于在线程之间同步共享数据的值
当某个共享数据达到某个值的时候,唤醒等待这个共享数据的线程

四、多线程环境
1、可重入函数:如果一个函数能被多个线程调用且不发生竞态条件,则是线程安全的,即是可重入函数
2、线程和进程
在多线程环境中,提供pthread_atfork函数,确保fork调用后父进程和子进程都拥有一个清楚地锁状态(见P302)
明确的将一个信号发送给指定的线程:int  pthread_kill(pthread_t  thread,  int  sig);
原创粉丝点击