linux 进程编程

一、进程的操作

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

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值