多进程编程
目的和要求 掌握Linux操作系统的进程创建等操作。 利用Linux操作系统提供的信号量工具实现进程间的同步。 掌握对共享内存的相关操作
进程的相关操作 头文件:#include <unistd.h> 进程创建函数:fork() 子进程中返回0,父进程中返回子进程ID,出错返回-1 。一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。 例:int pid=fork();
LINUX的IPC
LINUX的IPC SYSTEM V的IPC 信号量(semaphore set) 消息队列(message queue) 共享内存(shared memory) shell命令 ipcs, ipcrm访问
LINUX的IPC
创建信号量 头文件:#include <sys/sem.h> int semget(key_t key,int nsems,int semflg); 参数key表示所创建或打开信号量集的键 双方直接设置为一个相同的整数为key值 用IPC_PRIVA让系统自动产生一个key值, 用ftok函数将一个路径转换为key值 参数nsems表示创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效,几乎总是取值为1 参数flag表示调用函数的操作类型,也可用于设置信号量集的访问权限,两者通过or表示,IPC_CREAT, IPC_EXCL
信号量的操作semop() int semop(int semid,struct sembuf*sops,unsign nsops); semid为信号量集引用ID。 sops是一个sembuff结构数组,sembuff结构用于指定调用semop函数所作的操作,其中每个元素表是一个操作,由于此函数是一个原子操作,一旦执行就将执行数组中的所有操作 nsops:信号操作结构的数量,恒大于或等于1。
信号量的操作semop() struct sembuf { unsigned short sem_num; /* 信号量编号 */ short sem_op; /* 信号量操作 */ short sem_flg; /* 操作标志 */ } sem_flg用于对操作进行适当的控制,主要有2个控制标志。 IPC_NOWAIT 当指定的操作不能完成时,进程不等待立即返回,返回值为-1,errno置为EAGAIN。 SEM_UNDO(建议) 进程退出时,执行信号量解除(undo)操作。
P、V操作 s_empty = semget(IPC_PRIVATE,1,IPC_CREAT|IPC_EXCL|0777); int p(int semid) { struct sembuf sops={0,- 1, SEM_UNDO}; return (semop(semid,&sops,1)); } int v(int semid) struct sembuf sops={0, +1,ISEM_UNDO};
信号量的控制 int semctl(int semid,int semnum,int cmd,union semunarg); 第4个参数(可选) union semun{ int val; /*用于SETVAL命令,指明要设置的值*/ struct semid_ds *buf; /*用于IPC_STAT/IPC_IPC_SET命令,用来存放信号量集合数据结构*/ unsigned short *array; /*用于GETALL/SETALL命令,用来存放所获得的或是要设置信号量集合中所有信号量的值*/ } arg;
信号量的控制 “cmd” parameter IPC_STAT: 对指定的信号量标识返回arg.semid_ds结构中的当前值 IPC_SET: 在进程有足够权限的前提下,把信号量集合的当前关联值置为arg.semid_ds结构给出的值 IPC_RMID: 删除信号量集合 SETVAL: 设置信号量集合中由semnum指定的单个信号量的值(设为arg.val)
Linux共享内存
Linux共享内存 头文件:#include <sys/ipc.h> #include <sys/shm.h> 要使用一块共享内存,进程必须首先分配它。随后需要访问这个共享内存块的每一个进程都必须将这个共享内存绑定到自己的地址空间中。当完成通信之后,所有进程都将脱离共享内存,并且由一个进程释放该共享内存块。
分配共享内存 int shmget(key_t key, size_t size, int shmflg); key标识共享内存的键值 shmflg主要和一些标志有关。其中有效的包括IPC_CREAT和IPC_EXCL 。IPC_CREAT 如果共享内存不存在,则创建一个共享内存,否则打开操作。 IPC_EXCL 只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误
绑定地址空间 void *shmat( int shmid , char *addr , int shmflag ); 参数addr与flag组合说明要引入的地址值, addr为0,表明让内核来决定第1个可以引入的位置。addr非零,并且flag中指定SHM_RND,则此段引入到addr所指向的位置
控制共享内存 int shmctl( int shmid , int cmd , struct shmid_ds *buf ); int shmid:是共享内存的ID。 int cmd: 是控制命令,可取值如下: IPC_STAT 得到共享内存的状态, IPC_SET 改变共享内存的状态 IPC_RMID 删除共享内存 Shmid_ds为共享内存的结构
实例 #include <stdio.h> #include <sys/shm.h> #include <sys/stat.h> #define BUFSZ 4096 int main() { int segment_id; //共享内存标识 char* shared_memory; //进程的地址空间 int segment_size; /* 分配共享内存 */ segment_id = shmget(IPC_PRIVATE,BUFSZ, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR ); shared_memory = (char*)shmat(segment_id, 0, 0); /* 确定共享内存的大小 */ printf(“shared memory attached at address %p\n”, shared_memory); shmctl(segment_id, IPC_STAT, &shmbuffer); //得到共享内存的状态
实例 segment_size = shmbuffer.shm_segsz; printf("segment size: %d\n", segment_size); /* 在共享内存中写入一个字符串 */ sprintf(shared_memory, “Hello, world.”); shmdt(shared_memory); /* 脱离该共享内存块 */ /* 重新绑定该内存块 */ shared_memory = (char*)shmat(segment_id, 0, 0); printf("shared memory reattached at address %p\n", shared_memory); printf("%s\n", shared_memory); /* 输出共享内存中的字符串 */ shmdt(shared_memory); /* 脱离该共享内存块 */ shmctl(segment_id, IPC_RMID, 0);/* 释放这个共享内存块 */ return 0; }
End of Lab