进程和线程:#进程是操作系统对资源进行分配的基本单位,进程有完整的虚拟空间。进行系统资源分配的时候,除了CPU资源之外,不会给线程分配 独立的资源,
线程所需要的资源需要共享
#线程是进程的一部分,如果没有进行现实的线程分配,可以认为进程是单线程的,如果进程中建立了线程,认为进程是多现线程的#多线线程和多进程是两个不同概念,二者都是并行完成功能。多个线程之间像内存、变量等资源在多个线程之间进行简单的方法共享
而多进程之间的共享方式有限
#进程有进程控制表PCB,系统通过PCB对进城进行调度;线程有线程控制表TCB。TCB所表示的状态比PCB要少的多
进程:从操作系统看,是系统资源分配的最小单位。代表的是系统分配的内存,CPU时间片,等资源的基本单位
进程产生过程:1.复制父进程的环境配置
2.在内核中建立进程结构
3.将结构插入到进程列表
4.分配资源给此进程
5.复制父进程的内存映射信息
6.管理文件描述符和链接节点
7.通知父进程
进程终止方式(5种):1.从main返回
2.调用exit
3.调用_exit
4.调用abort
5.由一个终止信号终止
进程之间通信:管道,共享内存,消息队列。是三种最常用的方式
管道:利用内核在两个进程之间建立管道,特点类似文件操作,仅仅在管道的一端只读,另一端只写。利用读写的方式进行进程之 间传递数据
共享内存:将内存中的一段地址,在多个进程之间共享。多个进程利用获得的共享内存地址,直接对内存进行操作
消息:在内核中建立一个链表,发送方按照一定的标识将数据发送到内核中,内核将其放入链表后等待接收方的请求。接收方发送请 求后,内核按照消息的标识,从内核中将消息从链表中摘下,传递给接收方。消息是一种完全异步操作方式。
进程同步:多个进程之间血药协作完成任务时,涉及到进程之间同步问题。linux下进程同步方式主要有消息、信号量等
///一些函数///
#include<sys/types.h>
#include<unistd.h>
pid_t getpid(void); 获得当前进程的pid
pid_t getppid(void); 获得父进程的pid
/
fork()函数:以父进程为蓝本复制一个进程,其ID号与父进程不同,linux下fork是以写复制实现的,只有内存等与父进程不同,其他与父进程共享
|成功时返回进程ID,出错返回-1
#include<sys/type.h>
#include<unistd.h>
pid_t fork(void); //fork函数执行一次,返回两次,在父进程中返回子进程的ID,在子进程中返回0.
/
system() :调用shell的外部命令在当前进程中开始另一个进程。
system()函数调用"/bin/sh-c conmmand" 执行特定命令,阻塞当前进程直到command命令执行完毕。
#include <stdlib.h>
int system(const char *command)
|执行system函数的时候,会调用fork,execve,waitpid等函数,其中任意一个调用失败,将导致system()函数调用失败。
返回值: -1 出错
127 当sh不能执行时
进程状态值 成功返回
/
exec()函数:fork 和 system,创建进程,时创建一个新的进程,执行调用者进程还存在。exec()
函数会使新的进程替代原有的进程,系统从新的进程运行,新进程的pid与愿进程相同。
exec()函数族:
#include <unistd.h>
extern char **environ;
int execl(const char *path,connst char *arg,...);
int execlp(const char *file, const char *arg,...);
int execle(const char *path, const char *arg,..., char const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char 8const argv[]);
使用exec()的一种普遍方法,先使用fork函数分叉进程,然后在新的进程中调用exec()函数,这样会占用原来进程一样的系统资源来运行。
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\进程间通信和同步\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
进程间的通信机制叫做IPC,linux下有多重进程间的通信方法:半双工管道、FIFO(命名管道)、消息队列、信号量、共享内存。
//
#管道:pipe() 函数
#include <unistd.h>
int pipe(int filedes[2]);
fd0:读描述符,fd1:写描述符 |执行成功时返回0,出错返回-1
/
FIFO 命名管道:
shell中创建FIFO,使用mkfifo口;口令
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode)
/
消息队列:通过linux内核在进程之间传递消息,每个消息队列由IPC标识符唯一标识。每个消息队列中的消息独立构成链表。
消息通过内核进行转发时,内核不对mtext的内容进行转换,任意的消息都能发送,但消息的大小存在内部限制 MSGMAX (8192)
消息缓冲区结构:
struct msgbuf{
long mtype; //正整数,用于设置消息类型
char mtext[]; //消息数据,自己设定消息结构时,数据类型大小可变
}
//
#include <sys/types.h>
#include <ipc.h>
key_t ftok(const cahr *pathname, int proj_id);
pathname 是已经存在的目录, proj_id时一个8位的值,通常用a,b等表示。
//
msgget()函数:创建一个新的消息队列,或者访问已存在的消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
msgflg:IPC_CREAT 内核中不存在该队列则创建他,返回新的标识符,或者返回现有的标识符 |成功返回消息队列标识符,失败-1
IPC_EXCL 与ipc_creat一起使用,如果队列已存在,将出错
//发送消息
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msgqid, const void *msgp, size_t msgsz, int msgflg )
msgqid:消息队列标识符;msgp:指向消息缓冲区; msgflg:IPC_NOWAIT设置时,如果消息队列已满,则消息不回写入队列中。也可设置为0,
队列满时,调用进程阻塞至可写入消息。
\\\\\\\
信号量:信号量是一种计数器,用于控制对多个进程共享的资源所进行的访问。他们常被用作锁机制,在某个进程在访问某个资源时,防止其他
的进程对资源进程访问。
//信号量数据结构
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *_buf;
}
//新建信号量函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key,int nsems,int semflg);
nsems 指定在新集合中创建信号量的数目,semflg 参数:IPC_CREAT 如果不存在信号量集合就创建。
IPC_EXCL | IPC_CREAT 如果信号量已经存在就返回错误
typedef int sem_t;
union semun{
int val;
struct semid_ds;
unsigned short *arry; //数组类型
} arg;
建立信号量
sem_t CreatSem(ket_t key,int value){
union semun sem;
semt_t semid;
sem.val = value;
semid = semget(key,0,IPC_CREAT|0666);
if(-1 == semid)
{
printf("sem creat filed!");
return -1 ;
}
semctl(semid,0,SETVAL,sem) //建立value个初始值的信号量
return semid; //返回建立的信号量
}
//
信号量的P、V操作,是通过向已经建立好的信号量发送命令来完成的。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int sem_id,struct sembuf *sops,unsigned nsops);
struct sembuf{
ushort sem_num
}
指针sops,指向一个将要在信号集合上进行的操作的一个数组,nops 操作数组中操作的个数