一、进程的操作
1、进程的创建
父进程与子进程之间的关系是管理与被管理,当子进程终止时,父进程不一定终止;父进程终止时子进程一定终止。
Linux系统启动时只有一个进程:init进程,进程号为1。
可以通过getpid()获取自身运行的进程ID,通过getppid()获取父进程的ID。
这两个函数在头文件<unistd.h>当中。
printf("Process ID :%d\n",(int)getpid());
2、fork()函数
创建经常一般有两种方法:system()和fork()函数。
pid_t fork();
一个进程通过fork()函数会创建一个子进程,这个子进程和父进程只有进程ID不同,其他都一样,若子进程创建失败,则fork()函数返回-1,若创建成功则在子进程中返回0,在父进程中返回子进程的ID。
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
pid_t child_pid;
child_pid =fork();
switch (child_pid)
{
case -1:
printf("Create Process failed!\n");
break;
case 0:
printf("child Proces with ID %d\n",(int)getpid());
break;
default:
printf("Parent Process with %d,child Proces Id:%d\n",(int)getppid(),getpid());
break;
}
return 0;
}
3、进程的管理与调度
Linux下管理进程的命令有:at bg fg jobs kill ps pstree top noce sleep
4、进程的终止
子进程运行完毕后,并不立即释放所占用的进程控制表项,而作为僵进程存在,直到父进程终止或者调用wait()函数终止。
pid_t wait(int *status)
wait()函数会让父进程阻塞自己,分析已经退出的子进程,wait()函数会返回子进程结束状态值,如果没有找到一个这样的子进程,会一直阻塞。status 会储存子进程结束信息。
另一个函数waitpid(),可以设定参数设置让指定的子进程终止。
pid_t waitpid(pid_t pid,int *status,int option);
WIFEXITED(status)
能够判断子进程是否正常结束,如果正常结束,则返回个非0值。
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
pid_t child_pid,pid;
int status;
child_pid=fork();
switch (child_pid)
{
case -1:
printf("Creadte Process failed\n");
break;
case 0:
printf("child Process with ID %d\n",(int)getpid());
break;
default:
printf("Parent Process with ID %d,Child Process with ID %d",(int)getpid(),(int)child_pid);
pid=wait(&status);
printf("Child Process finished:PID=%d\n",child_pid);
if(WIFEXITED(status))
printf("ChildProcess exited with code %d\n",WEXITSTATUS(status));
else
printf("Child Process Terminated Abnormally\n");
break;
}
return 0;
}
二、进程间的通信
1、信号
定义在头文件<signal.h>中
用kill -l 可以查看所有信号。
可以通过signal()或者sigaction()函数设定某个信号的处理方法。
void (*signal(int signum,void(*handler)(int)))(int);
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact);
第一个参数为信号值,可以为除SIGKILL SIGSTOP外的信号;第二个参数是指向结构的一个实例指针,指定对特定信号的处理,可以为空;第三个参数指向的对象用来保存对相应信号的处理,可以设定为NULL。
信号的使用主要步骤为:安装信号,实现信号,处理函数,发送信号。信号的生命周期从信号发送开始,到相应的处理函数结束。
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<sys/time.h>
void SignalHandle(int signal) //信号处理函数
{
switch (signal)
{
case SIGHUP:
printf("Catch Signal: SIGHUP(%d)\n",signal);
break;
case SIGINT:
printf("Catch Signal:SIGINT(%d)\n",signal);
break;
case SIGQUIT:
printf("Catch Signal:SIGQUIT(%d)\n",signal);
break ;
case SIGALRM:
printf("Catch Signal :SIGALRM(%d)\n",signal);
break;
default:
printf("UNknow Signal:%d",signal);
break;
}
}
int main()
{
int sec_delay=5;
printf("Current Process Id:%d\n",(int)getpid());
signal(SIGQUIT,SignalHandle);
signal(SIGALRM,SignalHandle);
alarm(sec_delay); //5s后输出
while(1)
pause();
return 0;
}
2、命名管道命令
管道一端顺序写入数据,另一端顺序读数据,数据只能向一个方向流动,所以要双方通信要两个管道。
命名管道利用建立系统特殊文件,以FIFO的文件形式存在,一般使用mkfifo()函数创建相应的文件。
int mkfifo(const char* pathname,mode_t mode);
第一个参数是文件路径,mode是打开方式。
#include<unistd.h>
#include<fcntl.h>
#include<limits.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define FIFO_HANDLE_NAME "/tmp/fifo_hanfle"
#define FIFO_CLIENT_NAME "/tmp/fifo_client_%d "
struct ps_fifo_struct{
pid_t pid;
char str[64];
};
int main()
{
int fifo_handle,fifo_client;
struct ps_fifo_struct ps_fifo;
char client_fifo_name[64];
fifo_handle=open(FIFO_HANDLE_NAME,O_WRONLY);
if(fifo_handle==-1)
{
fprintf(stderr,"Open handle fifo failed\n");
exit(EXIT_FAILURE);
}
ps_fifo.pid=getpid();
memset(client_fifo_name,0,64);
sprintf(client_fifo_name,FIFO_CLIENT_NAME,ps_fifo.pid);
if(access(client_fifo_name,F_OK)==-1){
if(mkfifo(client_fifo_name,0777)!=0){
fprintf(stderr,"Could not create fifo %s\n",client_fifo_name);
exit(EXIT_FAILURE);
}
}
sprintf(ps_fifo.str,"hi,I'm %d",ps_fifo.pid);
printf("%d sent:\'%s'.\n",ps_fifo.pid,ps_fifo.str);
write(fifo_handle,&ps_fifo,sizeof(ps_fifo));
fifo_client=open(client_fifo_name,O_RDONLY);
if(fifo_client!=-1){
if(read(fifo_client,&ps_fifo,sizeof(ps_fifo))>0)
printf("received from %d:%s\n",ps_fifo.pid,ps_fifo.str);
close(fifo_client);
}
close(fifo_handle);
unlink(client_fifo_name);
exit(EXIT_SUCCESS);
}
#include<unistd.h>
#include<fcntl.h>
#include<limits.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define FIFO_HANDLE_NAME "/tmp/fifo_hanfle" //fifo 文件
#define FIFO_CLIENT_NAME "/tmp/fifo_client_%d "
struct ps_fifo_struct{
pid_t pid; //进程的PID
char str[64]; //对应的FIFO文件名
};
int main()
{
int fifo_handle,fifo_client;
char client_fifo_name[64];
char answer_str[64];
struct ps_fifo_struct ps_fifo;
int read_len;
//如果文件不存在且建立文件失败
if(access(FIFO_HANDLE_NAME,F_OK)==-1)
{
if(mkfifo(FIFO_HANDLE_NAME,0777)==-1){
fprintf(stderr,"Could not create fifo %s\n",FIFO_CLIENT_NAME);
exit(EXIT_FAILURE);
}
}
fifo_handle=open(FIFO_HANDLE_NAME,O_RDONLY);//打开处理的fifo文件
if(fifo_handle==-1)
{
fprintf(stderr,"Open handle fifo failed\n");
exit(EXIT_FAILURE);
}
while(read_len>0)
{
read_len=read(fifo_handle,&ps_fifo,sizeof(ps_fifo)); //读取文件里的内容
memset(answer_str,0,64);
if(read_len>0){
sprintf(answer_str,"hi,%d,Ihavereceivedhestring:'%s'.",ps_fifo.pid,ps_fifo.str);
printf("received from %d:%s\n",ps_fifo.pid,ps_fifo.str);
memset(client_fifo_name,0,64);
sprintf(client_fifo_name,FIFO_CLIENT_NAME,ps_fifo.pid);
fifo_client=open(client_fifo_name,O_WRONLY); //打开对应的另一个进程的文件
ps_fifo.pid=getpid();
sprintf(ps_fifo.str,answer_str);
if(fifo_client!=-1){
write(fifo_client,&ps_fifo,sizeof(ps_fifo)); //写入这个文件当中
close(fifo_client);
}
}
}
close(fifo_handle);
unlink(FIFO_HANDLE_NAME);
exit(EXIT_SUCCESS);
}
3、信号量
主要用来控制多个进程对临界资源的互斥访问,信号量是一种进程的同步机制。
key_t ftok(char *pathname,char proj);
int semget(key_t key,int nsems,int semflg);
int semop(int semid,struct sembuf *spos,int nspos);
int semctl(int semid,int semnum,int cmd,union semun arg);
ftok()函数创建一个关键字,成功时返回一个键值,失败时返回-1.
semget()函数创建一个新的信号量或者取得一个现有的信号量。
nsems表明创建信号量的个数。
semflg设置信号量的访问权限标志,调用成功返回信号量的ID,失败返回-1.
semop用于改变信号量键值,semid是信号标志,spos是表明进行什么操作的结构指针,nspos表示数组元素的个数。
semctl()对信号量进行一系列的控制,SETVAL 设置信号量的值,IPC_RMID删除信号量。
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#define SEM_PATHNAME "/tmp/my_sem"
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
struct semfifo *__buf;
void *__pad;
};
int main(int argc,char *argv[])
{
int sem_id,sem_key;
union semun arg_ctl;
struct sembuf sem_bufinfo;
int option_get=IPC_CREAT|IPC_EXCL|0666;
sem_key=ftok(SEM_PATHNAME,'X');
sem_id=semget(sem_key,1,option_get);
printf("semaphore id=%d.\n",sem_id);
arg_ctl.val=1;
if(-1==semctl(sem_id,0,SETVAL,arg_ctl))
perror("semctl error");
printf("value of semaphore at index 0 is %d.\n",semctl(sem_id,0,GETVAL,arg_ctl));
sem_bufinfo.sem_num=0;
sem_bufinfo.sem_op=-1;
sem_bufinfo.sem_flg=IPC_NOWAIT;
semop(sem_id,&sem_bufinfo,1);
printf("value of semaphore at index 0 is %d \n",semctl(sem_id,0,GETVAL,arg_ctl));
return 0;
}
4、信号队列
消息队列是将消息按队列的方式组成链表。
int msgget(key_t key,int msgflg);
int msgsnd(int msqid,const void *msgptr,int msgsz,int msgflg);
int msgrcv(int msqit,void *msgptr,int msgsz,long msgtyp,int msgflg);
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
#include<sys/types.h> #include<sys/msg.h> #include<unistd.h> #include<stdlib.h> #include<stdio.h> int main() { int msg_id,msg_flags; int reval; char send_msg[64]; msg_flags=IPC_CREAT|0666; msg_id=msgget((key_t)456,msg_flags); //建立消息队列 sprintf(send_msg,"Hi,I am%d.",getpid()); reval=msgsnd(msg_id,send_msg,sizeof(send_msg),0); //将消息发送到队列中 return 0; }
#include<sys/types.h> #include<sys/msg.h> #include<unistd.h> #include<stdlib.h> #include<stdio.h> int main() { int msg_id,msg_flags; int reval; char send_msg[64]; msg_flags=IPC_CREAT|0666; msg_id=msgget((key_t)456,msg_flags); //建立消息队列 reval=msgrcv(msg_id,send_msg,64,0,0); printf("Received msg:%s\n",send_msg); reval=msgctl(msg_id,IPC_RMID,0); return 0; }
5、共享内存
在linux中只要吧共享内存段连接到进程的地址空间中,这个进程就可以访问共享内存中的地址。
1、int shmget(key_t key,int shmsz,int shmflg);
该函数分配一块共享内存,shmsz指明共享内存的大小,shmflg的设置和其他函数中的类似。
如果调用成功则返回共享内存的ID,否则-1;
2、void *shmat(int shmid,const void *shmaddr,int shmflg);
该函数用老连接共享内存和地址空间
3、int shmdt(const void *shmaddr);
用来解除进程和共享内存的关联。
4、int shmctl(int shmid,int cmd,struct shmid_ds *buf);
实现对共享内存区域的操作控制。