Linux高性能服务器编程
13 多进程编程
#include
#include
pid_t fork(void);
子进程的代码和父进程完全相同,同时它还会复制父进程的数据(堆栈数据和静态数据),数据的复制采用写时复制(copy on write);
父进程打开的文件描述符在子进程中也打开,且文件描述符引用计数加1.且父进程的用户根目录、当前工作目录等变量的引用计数均会加1.
在子进程中执行其他程序,即替换当前进程映像:
#include
extern char** environ;
int execl(const char* path, const 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* const argv[]);
int execve(const char* path, char* const argv[], char* const envp[]);
exec函数不会关闭原程序打开的文件描述符,除非该文件描述符被设置了类似SOCK_CLOEXEC的属性。
#include
#include
pid_t wait(int* stat_loc);//将阻塞进程
pid_t waitpid(pid_t pid, int* stat_loc, int options);//可以设置WNOHANG参数
管道:父子间进程进行相互通信。
只能保证在一个方向上进行数据传输。
int pipefd[2];
pipe(pipefd);
//其中pipefd[0]读数据pipefd[1]写数据
socketpair();
struct ipc_perm{
key_t key;
uid_t uid;
gid_t gid;
uid_t cuid;
gid_t cgid;
mode_t mode;
};
信号量:pv操作
#include
int semget(key_t key, int num_sems, int sem_flags);
struct semid_ds{
struct ipc_perm sem_perm;
unsigned long int sem_nsems;
time_t sem_otime;
time_t sem_ctime;
};
关联的重要的内核变量:
unsigned short semval;
unsigned short semzcnt;
unsigned short semncnt;
pid_t sempid;
int semop(int sem_id, struct sembuf* sem_ops, size_t num_sem_ops);
struct sembuf{
unsigned short int sem_num;
short int sem_op;
short int sem_flg;
};
int semctl(int sem_id, int sem_num, int command, ...);
第四个参数推荐使用的格式:
union semun{
int val;
struct semid_ds* buf;
unsigned short* array;
struct seminfo* __buf;
};
struct seminfo{
int semmni;//最多包含的信号量集个数
int semmns;//最多包含的信号量个数
int semmsl;//一个信号量集最多允许包含的信号量数目
int semopm;//semop一次最多能执行的sem_op操作数目
int semusz;//sem_undo结构体的大小
int semvmx;//最大允许的信号量值
int semaem;//最多允许的UNDO次数
};
特殊键值IPC_PRIVATE
semget的调用者可以给其key参数传递一个特殊的键值IPC_PRIVATE(其值为0),这样无论该信号量是否已经存在,semget都将创建一个新的信号量。(更好的名字:IPC_NEW)
共享内存
#include
int shmget(key_t key, size_t size, int shmflg);
struct shmid_ds{
struct ipc_perm shm_perm;
size_t shm_segsz;//共享内存大小,单位字节
__time_t shm_atime;//最后一次调用shmat的时间
__time_t shm_dtime;
__time_t shm_ctime;
__pid_t shm_cpid;
__pid_t shm_lpid;//最后一次执行shmat或shmdt操作的进程的pid
shmatt_t shm_nattach;//目前关联到此共享内存的进程数量
};
共享内存被创建/获取之后,我们不能立即访问它,而是需要先将它关联到进程的地址空间中。使用完共享内存之后,也需要将它从进程地址空间分离。
void* shmat(int shm_id, const void* shm_addr, int shmflg);
int shmdt(const void* shm_addr);
int shmctl(int shm_id, int command, struct shmid_ds* buf);
共享内存的POSIX方法:
利用mmap函数的MAP_ANONYMOUS标志我们可以实现父子进程间的匿名内存共享。通过打开同一个文件,mmap也可以实现无关进程之间的内存共享。linux提供了另外一种利用mmap在无关进程之间共享内存的方式。这种方式无须任何文件的支持,但需要如下函数创建或打开一个POSIX共享内存对象:
#include
#include
#include
int shm_open(const char* name, int oflag, mode_t mode);
shm_open的使用方法和open系统调用完全相同。
与打开文件最后需要关闭一样,由shm_open创建的共享内存对象使用完之后也需要被删除。这个过程通过如下函数实现:
int shm_unlink(const char* name);
该函数将name参数指定的共享内存对象标记为等待删除。当所有使用该共享内存对象的进程都使用ummap将它从进程中分离之后,系统将销毁这个共享内存对象所占据的资源。编译时需要指定链接选项-lrt。
消息队列:
#include
int msgget(key_t key, int msgflg);
struct msqid_ds{
struct ipc_perm msg_perm;
time_t msg_stime;
time_t msg_rtime;
time_t msg_ctime;
unsigned long __msg_cbytes;//消息队列已有的字节数
msgqnum_t msg_qnum;//消息队列已有的消息数
msglen_t msg_qbytes;//消息队列允许的最大字节数
pid_t msg_lspid;
pid_t msg_lrpid;
};
int msgsnd(int msgqid, const void* msg_ptr, size_t msg_sz, int msgflg);
struct msgbuf{
long mtype;
char mtext[512];
};
支持IPC_NOWAIT参数
int msgrcv(int msqid, void* msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
int msgctl(int msqid, int command, struct msqid_ds* buf);
阅读(1348) | 评论(0) | 转发(0) |