linux 进程编程

来源:互联网 发布:枪神纪刷枪软件2016 编辑:程序博客网 时间:2024/06/14 08:11

一、进程的操作

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);

实现对共享内存区域的操作控制。