《Linux学习笔记》:进程

一、进程

1.查看进程的代码

1.1 ps指令

ps -ef    //查看所有进程的 PID(进程号 ,PPID副进程号 ) 、系统时间、命令详细目录、执行者
ps -aux    //查看所有进程的 PID(进程号 ,PPID副进程号 ) 、系统时间、命令详细目录、执行者、CPU、GPU占用率
ps axj    //查看进程多了PPID PPID是父进程
pstree    //进程进行树状图显示
 

1.2 PPID:父进程       PID:为子进程

注意:通常父进程的pid要小于子进程,因为父进程先有,再创建子进程

1.3 创建子进程的函数fork()

创建子进程的函数

名称(NAME)

        fork - 创建一个子进程

概要(SYNOPSIS)

       #include <sys/types.h>
       #include <unistd.h>

       pid_t fork(void);

返回值(RETURN)

        成功时,父进程将返回子进程的PID(所以pid>0的时候可以代表是父进程),子进程将返回0。

        失败时,返回值为-1,在父进程中返回,不创建子进程,并适当地设置errno(可以使用perror进行错误原因输出)。

fork(),采用写时复制(copy on write) 

 写时复制Copy-on-write,简称COW)是一种计算机程序设计领域的优化策略。其核心思想是,如果有多个调用者(callers)同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的。此作法主要的优点是如果调用者没有修改该资源,就不会有副本(private copy)被创建,因此多个调用者只是读取操作时可以共享同一份资源。

1.4 进程的退出

1.5 阻塞函数

(1)wait

名称(NAME)

        wait - 调用该函数使进程阻塞,直到任意一个子进程结束或者该进程接收到一个信号为止。如果该进程没有子进程或者子进程已经结束,wait函数立刻返回。

概要(SYNOPSIS)

        #include <sys/types.h>

        #include <sys/wait.h>

        pid_t wait(int *status)

参数

        status是一个整型指针,指向的对象用水保存子进程退出时的状态。

        status若为空,表示忽略子进程退出时的状态。

        status若不为空,表示保存子进程退出时的状态另外,子进程的结束状态Linux中一些特定的宏来测定。

       

返回值(RETURN)

        成功:子进程的进程号
        失败:-1

        

(2)waitpid

名称(NAME)

        waitpid - 功能和wait函数类似。结束以及等待的方式可以指定等待某个子进程的等待方式(阻塞或非阻塞)

概要(SYNOPSIS)

        #inelude<sys/types.h>

        #include <sys/wait.h>

        pid_t waitpid(pid t pid, int *status, int options)

参数

        pid:

                pid>0:只等待进程ID等于pid的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
                pid=-1:等待任何一个子进程退出,此时和wait作用一样。
                pid=0:等待其组ID等于调用进程的组ID的任一子进程。
                pid<-1:等待其组ID等于pid的绝对值的任一子进程。

        status:

                同wait

        options:

                WNOHANG:若由pid指定的子进程并不立即可用,则waitpid不阻塞,此时返回值为0
                WUNTRACED:若某实现支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态
                0 : 同wait,阻塞父进程,等待子进程退出。

     

返回值(RETURN)

        正常:结束的子进程的进程号
        使用选项WNOHANG且没有子进程结束时:0
        调用出错:-1

        

 2.进程

2.1进程的概念

        进程是值一个具有独立功能的程序在某个数据集合上的以此动态执行的过程,是操作系统进行资源分配和调度的基本单元。一次任务的运行可以激活多个进程,这些进程相互合作来完成该任务的一个最终目标

2.2 进程和程序的区别

        进程和程序有本质的区别,程序是一段静态的代码。

        进程是程序一次执行的过程,包括了动态创建,调度,执行和消亡的整个过程。

2.3虚拟内存的优点

(1)多任务(2)安全

2.4进程是资源管理的最小单元

        每一个进程都有一个0-4G的虚拟内存

2.5进程是由进程创建的

        进程是由进程创建的

        2.5.1子进程的创建:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    pid_t pid=fork();

    while(1);
    return 0;
}

         2.5.2有关继承的调度机制问题:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
    pid_t pid=fork();
    if(pid>0)
    {
        while(1)
        {
            printf("parent!\n");
            sleep(1);
        }
    }
    else if(0==pid)
    {
        while(1)
        {
            printf("child!\n");
            sleep(1);
        }
    }
    return 0;
}

 可见其是具有某种不知道的规律进程抢占资源的(如下图)

        2.5.3关于父进程和子进程的缓冲区问题
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
    printf("缓冲中......");//第一次不注释此行,注释下一行
    /*printf("缓冲中...\n");//第二次不注释此行,注释上一行*/
    pid_t pid=fork();
    if(pid>0)
    {
        while(1)
        {
            printf("parent!\n");
            sleep(1);
        }
    }
    else if(0==pid)
    {
        while(1)
        {
            printf("child!\n");
            sleep(1);
        }
    }
    return 0;
}

  printf("缓冲中......");不注释,printf("缓冲中...\n");注释的结果,可以证明子进程会拷贝父进程的缓冲区

  printf("缓冲中......");注释,printf("缓冲中...\n");不注释

 

2.6进程的类型

        2.6.1交互进程

         由一个shell启动的进程,交互进程既可以在前台运行,也可也在后台运行。

        2.6.2批处理进程

        这种进程与终端无关,是一个进程的序列

        2.6.3守护进程:

        该进程在后台运行。他一般在Linux启动时开始创建,系统关闭时才结束。

        特点:

                (1)与终端不可以有亲缘关系

                (2)守护进程没有控制终端,标识符变成(?)

        创建守护进程的过程:

                (1)创建子进程,父进程退出

                        意义:使子进程与终端脱离关系,达成第一点,这时的子进程变成了孤儿进程由systmd收养(Ubuntu18.4之前的版本由init收养),代码如下

pid=fork();
if(pid>0)
{
    exit(0);//父进程退出
}

                (2)在子进程中创建新会话(setsid())        

                        意义:为了脱离所有其他进程的控制,因为,在使用fork()的时候全盘复制父进程的会话期、进程组,控制终端等,不是真正的独立。

                (3)改变当前目录为根目录(也可也更改为其他目录,更改目录的函数是chdir()

                        意义:为了防止后续进程运行时,无法对父进程所在的目录进行卸载等操作

                (4)重设文件权限掩码(通常umask(0)

                        意义:增强守护进程的灵活性,因为fork()函数使得子进程继承了父进程的文件掩码,这就给该进程使用文件带来了一定的影响

                (5)关闭文件描述符

                        意义:减少资源占用,同时防止所在的文件系统无法被卸载。具体是因为由于fork()会使该子进程从父进程继承来一些已经打开的文件,这些文件可能永远也不会被守护进程访问。


/*守护进程创建全部代码*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/stat.h>

int main(int argc, char const *argv[])
{
    
    char buf[50]="test[守护进程]\n";
    int i=0;
    int fp=0;
    //第一步,创建子进程,让父进程退出
    pid_t pid=fork();
    if(pid<0)
    {
        perror("fork error");
        exit(-1);//根据函数手册,异常退出return -1
    }
    else if(pid>0)
    {
        //父进程
        printf("父进程的PID为%d,现在将父进程退出\n",getpid());
        exit(0);//正常退出为0
    }
    
    //第二步,在子进程中创建新的会话
    setsid();
    //第三步,切换当前目录为根目录
    chdir("/tmp");
    //第四步,更改文件掩码,提高守护程序的自由度
    umask(0);
    //第五步,关闭文件描述符
    for ( i = 0; i < getdtablesize(); i++)
    {
        close(i);
    }
    
   //守护进程
    while(1)
    {
        printf("我已经脱离了中断,我打印不出来东西")//因为脱离了中断,所以打印不出来东西在屏幕
        fp=open("守护进程.log",O_WRONLY|O_APPEND);//这里我们先在设置的目录下创建好.log文件,以 只写|追加 打开文件
        if(fp<0)
        {
            perror("open error");
            exit(-1);
        }
        write(fp,buf,strlen(buf));
        close(fp);
        sleep(2);
    }
    
    exit(0);
}

 操作成功展示r

2.7进程的状态
        2.7.1运行状态(TASK_RUNNING):

        运行状态(TASK_RUNNING):

        2.7.2可中断的阻塞状态(TASK_INTERRUPTIBLE):

        进程处于阻塞(睡眠)状态,正在等待某些事件的发生,可以被信号中断唤醒,唤醒后变为TASK_RUNNING状态

        2.7.3不可中断发阻塞状态(TASK_UNINERRUPTIBLE0):

        只有等待的事情发生了才会被唤醒

        2.7.4暂停状态(TASK_STOPPED):

        收到 SIGSTOP、SIGSTP、SIGTTIN、SIGTTOU等信号便进入暂停状态

        2.7.5僵尸状态(EXIT_ZOMBIE):

        子进程先死亡,父进程没有及时回收也没有使用wait函数(waitpid()),处于该状态下的子进程,旨在进程列表中保留了一个位置,记载该进程的退出状态等信息供其父进程进行收集

        生成僵尸状态,代码如下:

/*创建一个僵尸进程的全部代码*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    pid_t pid=fork();
    if(pid<0)
    {
        perror("fork error");
        exit(-1);
    }
    else if(pid>0)
    {
        //父进程
        printf("parent\n");
        while(1);//挂起父进程,不退出
    }
    else if(0==pid)
    {
        printf("child is dead!\n");

    }
    return 0;
}

使用ps ajx查看一下,如下确实变成了僵尸状态

        避免僵尸进程的出现,我们可以:子进程结束的时候,父进程及时去回收,调用 wait 或者 waitpid
/*wait 避免僵尸进程出现*/

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>

int main()
{
    pid_t pid=fork();
    if(pid>0)
    {
        sleep(1);
        //阻塞函数
        wait(NULL);//忽略子进程的退出状态,若需要保留请定义一个int 变量,把地址给进去
        while(1)
        {
           printf("parent\n");
          sleep(2); 
        }
    }
    else if(0==pid)
    {
        int i=0;
        while(i<5)
        {
            i++;
            sleep(3);
            printf("child\n");
        }    
    }
    return 0;
}
/*waitpid 消除僵尸进程*/

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>

int main()
{
    pid_t pid=fork();
    if(pid>0)
    {
        sleep(1);
        //阻塞函数
        waitpid(-1,NULL,0);  
        while(1)
        {
           printf("parent\n");
           sleep(2); 
        }
    }
    else if(0==pid)
    {
        int i=0;
        while(i<5)
        {
            i++;
            sleep(3);
            printf("child\n");
        }    
    }
    return 0;
}
/*使用信号避免僵尸进程,最优*/
/*关于信号的知识,在下面进行讲述,可以先跳过此方法*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <wait.h>


void sig_child(int signum)
{
    if(sigum==SIGCHLD)
    {
    //处理僵尸进程
        if ((pid = waitpid(-1, &stat, WNOHANG)) >0)
	    {
            printf("正常退出\n");
        }
        else if ((pid = waitpid(-1, &stat, WNOHANG)) >0)
        {
            printf("其他原因\n");
        }
    } 
}
int main()
{
    //返回值大于0,退出
    //SIGCHLD
    //1.exit 返回值大于0,退出  2.等于0没有子进程退出   3.<0出错


    pid_t pid=fork();
    if(pid>0)
    {
         signal(SIGINT,sig_child);
 
        printf("parent\n");
        while(1)
        {
            printf("...\n");
            sleep(2);//转让占用权
        }
    }
    else if(0==pid)
    {
        printf("child\n");
    }
}

        2.7.6消亡状态(EXIT_DEAD):

        最终状态,父进程调用wait函数族回收之后,子进程彻底由系统删除

二、exce函数族

 

/*11_exce.c*/

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{

    pid_t pid=fork();
    if(pid<0)
    {
        perror("错误!\n");
        return -1;
    }
    else if(pid>0)
    {
        printf("parent!\n");
    }
    else
    {
        //执行新的程序
        execl("./hello","aaa",NULL);
        /*char *argv[]={"./hello","yyds",NULL};*/
        /*execv("./hello",argv);*/
   
    }
    while(1);
    return 0;
}

 

/*hello.c*/
#include <stdio.h>
int main(int argc,char **argv)
{
    printf("hello execl %s\n",argv[1]);
    return 0;
}

三、进程间的通信

1.管道

(1)无名管道

此后测试要用到好多头文件,为此我把这些头文件都放到自己新建的.h中去 

/*pipe.h*/

#ifndef _PIPE_H_
#define _PIPE_H_

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <wait.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#endif
/*11_单共通信_分时.c*/

#include "../pipe.h"

int main(int argc, char const *argv[])
{
    int fd[2]={-2,-2};
    int ret=pipe(fd);

    pid_t pid=fork();
    
    if(pid>0)
    {
        char buf[100]={0};
        printf("w_parent:");
        fgets(buf,sizeof(buf),stdin);
        write(fd[1],buf,sizeof(buf));
        sleep(1);
        memset(buf,0,sizeof(buf));
        read(fd[0],buf,sizeof(buf));
        printf("r_parent:%s",buf);
    }
    else if(0==pid)
    {
        char buf[100]={0};
        read(fd[0],buf,sizeof(buf));
        printf("r_child:%s",buf);
        memset(buf,0,sizeof(buf));
        printf("w_child:");
        fgets(buf,sizeof(buf),stdin);
        write(fd[1],buf,sizeof(buf));
    
        
        
        printf("r_parent:%s",buf);
    }
    return 0;
}

 当管道中没有数据的时,读操作会堵塞

当读操作不进行的时候,写操作会堵塞

当读端不存在,写入输出不具有意义,会导致管道破裂(收到SIGPIPE信号,Broken pipe)

/*测试管道破裂的情况*/
/*05_管道破裂.c*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
#include <stdlib.h>
int main()
{
    //子进程写,父进程监督子进程的退出状态
    int fd[2]={-2,-2};
    int ret=pipe(fd);//读取管道状态
    pid_t pid=fork();
    if(ret<0)
    {
        perror("pipe error");
        return -1;
    }
    
    close(fd[0]);
    if(pid==0)
    {
        //子进程 只有写
        char buf[50]={0};
        printf("写:");
        fgets(buf,sizeof(buf),stdin);
        write(fd[1],buf,sizeof(buf));
        exit(3);
     }
    else if(pid>0)
    {
        //父进程 没有读
        int status=0;
        /*int ret=waitpid(-1,&status,WUNTRACED);*/ 
        printf("ret=%d\n",ret);
        wait(&status);
        if(WIFEXITED(status))
        {
            printf("exit normally:%d\n",WEXITSTATUS(status));
        }
        else if(WIFSIGNALED(status))
        {
            printf("中断信号:%d\n",WTERMSIG(status));
        } 
    }
    return 0;
}

(2)有名管道

/*01_单工通信_w.c*/

#include "pipe.h"

int main()
{
    //父进程
    int ret=mkfifo("test.fifo",0777);
    if(ret<0&&EEXIST!=errno)
    {
        perror("mkfifo error");
        return -1;
    }

    int fw = open("test.fifo",O_RDWR);
    if(fw<0)
    {
        perror("open error");
        return -1;
    }
    char buf[100]={0};
    while(1)
    {
        memset(buf,0,sizeof(buf));
        printf("w:");
        fgets(buf,sizeof(buf),stdin);
        write(fw,buf,sizeof(buf));
        if(0==strncmp(buf,"quit",4))
        {
            break;
        }
    }
    close(fw);
    return 0;
}
/*02_单工通信_r.c*/

#include "pipe.h"

int main()
{
    int ret=mkfifo("test.fifo",0777);
    if(ret<0&&EEXIST!=errno)
    {
        perror("mkfifo error");
        return -1;
    }

    int fr = open("test.fifo",O_RDWR);
    if(fr<0)
    {
        perror("open error");
        return -1;
    }
    char buf[100]={0};
    while(1)
    {
        memset(buf,0,sizeof(buf));
        read(fr,buf,sizeof(buf));
        if(0==strncmp(buf,"quit",4))
        {
            break;
        }
        printf("r:%s",buf);
        fflush(stdin);
    }
    close(fr);
    return 0;
}

/*双管道双向通信.c*/
#include "pipe.h"

int main()
{
    pid_t pid=fork();
    if(pid>0)
    {
        //父进程
         int ret=mkfifo("test.fifo",0777);
         if(ret<0&&EEXIST!=errno)
          {
             perror("mkfifo error");
             return -1;
          }

    int fw = open("test.fifo",O_RDWR);
    if(fw<0)
    {
        perror("open error");
        return -1;
    }
    char buf[100]={0};
    while(1)
    {
        memset(buf,0,sizeof(buf));
        /*printf("w:");*/
        fgets(buf,sizeof(buf),stdin);
        write(fw,buf,sizeof(buf));
        if(0==strncmp(buf,"quit",4))
        {
            break;
        }
    }
    close(fw);
    }
    else if(0==pid)
    {
        //子进程
    int ret=mkfifo("test.fifo",0777);
    if(ret<0&&EEXIST!=errno)
    {
        perror("mkfifo error");
        return -1;
    }

    int fr = open("test.fifo",O_RDWR);
    if(fr<0)
    {
        perror("open error");
        return -1;
    }
    char buf[100]={0};
    while(1)
    {
        memset(buf,0,sizeof(buf));
        read(fr,buf,sizeof(buf));
        if(0==strncmp(buf,"quit",4))
        {
            break;
        }
        printf("%s",buf);
        fflush(stdin);
    }

    }
    return 0;
}

2.信号

名称(NAME)

        signal - 用于信号的安装、注册和自定义

概要(SYNOPSIS)

        #include <signal.h>

        void (*signal(int signum, void (*handler)(int))(int);

参数

        signum:

                指定信号
        handler:
               
 SIG IGN:忽略该信号。
                SIG DFL:采用系统默认方式处理信号。
                自定义的信号处理函数指针 

       

返回值(RETURN)

        成功:设置之前的信号处理方式
        出错:-1

        

/*测试信号函数*/
#include <stdio.h>
#include <unistd.h>
#include <signal.h>


//自定义信号处理函数
void sigFunc(int signum)
{
    if(signum==SIGINT)//终端中的ctrl+c 被重新定义
    {
        printf("收到信号\n");
    }
  /*  else if(signum==SIGKILL)//SIGKILL无法自定义
    {
        printf("收到了SIGKILL这个信号\n");
    }*/
    else if(signum==SIGQUIT)
    {
        printf("收到了SIGQUIT的信号\n");
    }
    else if(signum==SIGBUS)
    {
        printf("收到了SIGBUS的信号\n");
    }
}

int main()
{
    //注册信号    
    /*signal(SIGINT,SIG_IGN);*/
    /*signal(SIGINT,SIG_DFL);*/
    signal(SIGINT,sigFunc);//自定义收到信号后,对信号的操作
    /*signal(SIGKILL,SIG_IGN);//SIGKILL无法忽略*/
    /*signal(SIGKILL,sigFunc);//SIGKILL无法自定义*/
    signal(SIGQUIT,sigFunc);
    signal(SIGBUS,sigFunc);
    while(1)
    {
        printf("hll\n");
        sleep(1);
    }

}

名称(NAME)

        alarm - 该信号当一个定时器到时的时候发出终止

概要(SYNOPSIS)

        #include <unistd.h>
        unsigned int alarm(unsigned int seconds)

参数

       seconds:指定秒数

       

返回值(RETURN)

        成功:如果调用此alarm0前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。
        出错:-1

        

/*测试alarm闹钟函数*/

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void sigFunc(int signum)
{
    if(signum==SIGALRM)
    {
        printf("关闭空调\n");
    }
}

int main()
{
    signal(SIGALRM,sigFunc);//自定义信号
    alarm(3);//默认操作是停止函数发出信号signal alarm,打出Alarm cloock
    //注册信号
    while(1)
    {
        printf("...\n");
        sleep(1);
    }
}

名称(NAME)

        pause - 函数是用于将调用进程挂起直到收到信号为止。

概要(SYNOPSIS)

        #include <unistd.h>
        int pause(void); 

       

返回值(RETURN)

        -1,并且把error值设为EINTR

        

/*测试pause挂起函数*/

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void signFunc(int signum)
{
    if(SIGALRM==signum)
    {
        printf("不盖盖儿\n");
    }
}

int main()
{
    signal(SIGALRM,signFunc);
    alarm(5);
    printf("泡面\n");
    pause();
    printf("劲道\n ");
    return 0;
}

名称(NAME)

        kill - 给别的进程 or 进程组发送信号

概要(SYNOPSIS)

        #include <signal.h>
        #include <sys/types.h>
        int kill(pid t pid, int sig);

参数

        pid:

                正数:要接收信亏的进程的进程号
                0:信亏被发送到所有和pid进程在同一个进程组的进程
                -1:信号发给所有的进程表中的进程(除了进积号最大的进程外)
                sig:信号

       

返回值(RETURN)

        成功:0
        出错:-1

        

名称(NAME)

        raise - 给自己发送信号

概要(SYNOPSIS)

        #include <signal.h>
        #include <sys/types.h>
        int raise(int sig):

参数

       sig:信号

       

返回值(RETURN)

        成功:0

        出错:-1

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
int main()
{
    /*int fd[2]={-2,-2};*/
    pid_t pid=fork();
    int i=0;
    if(pid>0)
    {
        sleep(1);
        while(1)
        {
            if(i==15)
            { //启动子进程
                 printf("启动子进程:%d\n",pid);
                 kill(pid,18);
            }
            i++;
            sleep(1);
            printf("parent..\n");
        }
    }

    else if(pid==0)
    {
        int ChilId=getpid();
        while(1)
        { 
            if(i==10)
            { 
                printf("暂停自己:%d\n",ChilId);
                 raise(19);
            }
            i++;
            sleep(1);
            printf("child..\n");
        } 

    }
}

3.共享内存

 (1)单次读写


/*shm_r.c*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <stdlib.h>
int main()
{

    //获取key值
    key_t key=ftok(".",8);
    
    //创建共享内存
    int shmID=shmget(key,100,IPC_CREAT|0666);
    
    printf("shmID=%d\n",shmID);
    //映射共享内存
    void *pAddr=shmat(shmID,NULL,0);
    //操作
    printf("r:");
    printf("%s\n",(char *)pAddr);
    //取消映射
    shmdt(pAddr);
    //删除
    shmctl(shmID,IPC_RMID,NULL);
    
    system("ipcs -m");
}
/*shm_w.c*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <signal.h>
void sig_func(int SigNum)
{
    if(SIGUSR1==sigNum)
    {
         
    }
}

int main()
{

   
    signal(SIGUSR1,sig_func)
    //获取key值
    key_t key=ftok(".",8);
    
    //创建共享内存
    int shmID=shmget(key,100,IPC_CREAT|0666);
    
    printf("shmID=%d\n",shmID);
    //映射共享内存
    void *pAddr=shmat(shmID,NULL,0);
    //操作
    while(1)
    {
         pause();
         printf("w:");
         scanf("%s",(char *)pAddr);
    }
    //取消映射
    shmdt(pAddr);

    system("ipcs -m");
}

 (2)多次读写

/*shm_r.c*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
void sig_func(int SigNum)
{
    if(SIGUSR1==SigNum)
    {
         printf("r:");
    }
}
int main()
{

    //获取key值
    key_t key=ftok(".",8);
    
    //创建共享内存
    int shmID=shmget(key,100,IPC_CREAT|0666);
    
    printf("shmID=%d\n",shmID);
    //映射共享内存
    void *pAddr=shmat(shmID,NULL,0);
    //操作
     
    signal(SIGUSR1,sig_func);
    //读本文件ID,用于r文件传信号
    *(int *)pAddr=getpid();
    //写出共享内存的东西
    //先挂起
    while(1)
    {
        pause(); 
        printf("%s\n",(char *)pAddr);
        if(strcmp((char *)pAddr,"quit")==0)
        {
            break;
        } 
    }
    //取消映射
    shmdt(pAddr);
    //删除
    shmctl(shmID,IPC_RMID,NULL);
    
    system("ipcs -m");
}

 

/*shm_w.c*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <string.h>
int main()
{

    //获取key值
    key_t key=ftok(".",8);
    
    //创建共享内存
    int shmID=shmget(key,100,IPC_CREAT|0666);
    
    printf("shmID=%d\n",shmID);
    //映射共享内存
    void *pAddr=shmat(shmID,NULL,0);
    //操作
    
    //读另外一个进程的id
    int pid=*(int*)pAddr;
    printf("读文件的ID为:%d\n",pid); 
    //往共享内存中写入东西
    while(1)
    {

        printf("w:");
        scanf("%s",(char *)pAddr);
        kill(pid,SIGUSR1);
         
        if(strcmp((char *)pAddr,"quit")==0)
        {
            break;
        }
    }
    //取消映射
    shmdt(pAddr);

    system("ipcs -m");
}

4.信号量 

 

 

/*sem_r.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h> 
#include <semaphore.h>
#include <string.h>
int main()
{
    // 创建有名信号量
    sem_t *pSem1=sem_open("text01.data",O_CREAT|O_RDWR,0666,1);
    sem_t *pSem2=sem_open("text02.data",O_CREAT|O_RDWR,0666,0);
    
    //1.创建并且打开共享内存
    //获取key的值
    key_t key=ftok(".",8);
    
    printf("key=%d\n",key);
    int shmID=shmget(key,100,IPC_CREAT|0666);
    printf("shmID=%d\n",shmID);
    //2.映射共享内存
    void *pAddr=shmat(shmID,NULL,0);
    //3.操作
    while(1)
    {
        sem_wait(pSem2);
        printf("r:");
        printf("%s\n",(char *)pAddr);
        sem_post(pSem1);
      if(strcmp((char *)pAddr,"quit")==0)
    {
        break;
    }
    }

    //4.取消映射
    shmdt(pAddr);
    //5.删除共享空间
    shmctl(shmID,IPC_RMID,NULL);
}
/*sem_w.c*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <semaphore.h>
#include <string.h>
int main()
{
    // 创建有名信号量
    sem_t *pSem1=sem_open("text01.data",O_CREAT|O_RDWR,0666,1);
    sem_t *pSem2=sem_open("text02.data",O_CREAT|O_RDWR,0666,0);
    
    //1.创建并且打开共享内存
    //获取key的值
    key_t key=ftok(".",8);
    if(key<0)
    {
        perror("ftok error");
        return -1;
    } 
    printf("key=%d\n",key);
    int shmID=shmget(key,100,IPC_CREAT|0666);
    if(shmID<0)
    {
        perror("shmget error");
        return -1;
    }
    printf("shmID=%d\n",shmID);
    //2.映射共享内存
    void *pAddr=shmat(shmID,NULL,0);
    if((void *)-1 ==pAddr)
    {
        perror("shmat error");
        shmctl(shmID,IPC_RMID,NULL);
        return -1;
    }
    //3.操作
    while(1)
    {
         sem_wait(pSem1);
         printf("w:");
         scanf("%s",(char *)pAddr);
         sem_post(pSem2);
         
  if(strcmp((char *)pAddr,"quit")==0)
    {
        break;
    }
    }

    //4.取消映射
    shmdt(pAddr);
}

 

5.消息队列

 (1)单进程

/*msg_r.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define N 50

typedef struct msgbuf
{
    long mType;
    char mText[N];
}Msg;

int main(int argc, char const *argv[])
{
    //1.创建并打开消息队列
    key_t key=ftok(".",6);
    if(key<0)
    {
        perror("ftok error");
        return -1;
    }
    int msgID=msgget(key,IPC_CREAT|0664);
    if(msgID<0)
    {
        perror("msgget error");
        return -1;
    }
    //2.添加消息
    int i=0;
    Msg msg={0};
    for(i=0;i<3;i++)
    {
        int ret=msgrcv(msgID,(void *)&msg,sizeof(msg.mText),0,0);
        if(ret<0)
        {
            perror("msgsnd error");
            //删除队列消息
            msgctl(msgID,IPC_RMID,NULL);
        }
        printf("mType is %ld,mTest is %s\n",msg.mType,msg.mText);
    }
    //删除消息队列
    msgctl(msgID,IPC_RMID,NULL);
    return 0;
}

 

/*msg_w.c*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define N 50

typedef struct msgbuf
{
    long mType;
    char mText[N];
}Msg;

int main(int argc, char const *argv[])
{
    //1.创建并打开消息队列
    key_t key=ftok(".",6);
    if(key<0)
    {
        perror("ftok error");
        return -1;
    }
    int msgID=msgget(key,IPC_CREAT|0664);
    if(msgID<0)
    {
        perror("msgget error");
        return -1;
    }
    //2.添加消息
    int i=0;
    Msg msg={0};
    for(i=0;i<3;i++)
    {
        printf("请输入(msg.mType,msg.mText)\n");
        scanf("%ld,%s",&msg.mType,msg.mText);
        int ret=msgsnd(msgID,(void *)&msg,sizeof(msg.mText),0);
        if(ret<0)
        {
            perror("msgsnd error");
            //删除队列消息
            msgctl(msgID,IPC_RMID,NULL);
        }
       
    }
    //删除消息队列
    //msgctl(msgID,IPC_RMID,NULL);
    return 0;
}

 (2)多进程

/*msg_r.c*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <wait.h>
#define N 50

typedef struct msgbuf
{
    long mType;//消息类型
    char mText[N];
}Msg;

int main(int argc, char const *argv[])
{
    //1.创建并打开消息队列
    key_t key=ftok(".",6);
    if(key<0)
    {
        perror("ftok error");
        return -1;
    }
    int msgID=msgget(key,IPC_CREAT|0664);
    if(msgID<0)
    {
        perror("msgget error");
        return -1;
    }

    //pid_t pid=fork();

   while (1)
   {
  
   pid_t pid=fork();
    if(pid>0)
    {
        Msg msg={200};
        //父进程 发送100
        printf("请输入(200.mText)\n");
        scanf("%s",msg.mText);
        int ret=msgsnd(msgID,(void *)&msg,sizeof(msg.mText),0);
        wait(NULL);
    }
    
    else if(0==pid)
    {
        //子进程 接收100
        
       
        Msg msg={100,0};
        printf("代号100:");
        int ret=msgrcv(msgID,(void *)&msg,sizeof(msg.mText),100,0);
        printf("mType is %ld,mTest is %s\n",msg.mType,msg.mText);
    
    }
   
   }
    return 0;
    
}

 

/*msg_w.c*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <wait.h>
#define N 50

typedef struct msgbuf
{
    long mType;
    char mText[N];
}Msg;

int main(int argc, char const *argv[])
{
   
    //1.创建并打开消息队列
    key_t key=ftok(".",6);
    if(key<0)
    {
        perror("ftok error");
        return -1;
    }
    int msgID=msgget(key,IPC_CREAT|0664);
    if(msgID<0)
    {
        perror("msgget error");
        return -1;
    }
    //2.添加消息
   
    //pid_t pid=fork();

while (1)
{
    pid_t pid=fork();

    if(pid>0)
    {
        
         Msg msg={100};
        //父进程 发送100
        printf("请输入(100.mText)\n");
        scanf("%s",msg.mText);
        int ret=msgsnd(msgID,(void *)&msg,sizeof(msg.mText),0);
       // wait(NULL);
    }
    else if(0==pid)
    {
        Msg msg={200,0};
        printf("代号200:");
        int ret=msgrcv(msgID,(void *)&msg,sizeof(msg.mText),200,0);
        printf("mType is %ld,mTest is %s\n",msg.mType,msg.mText);
    }
}   
    return 0;

}

四、线程

 (1)线程的同步

/*pthread.c*/

#include <stdio.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>

sem_t pSem1;
sem_t pSem2;
sem_t pSem3;



void *threadFunc1(void *argv)
{
    while(1)
    {
        sem_wait(&pSem1);//1
        printf("视频采集!\n");
        sleep(1);
        sem_post(&pSem2);
    }
}

void *threadFunc2(void *argv)
{
    while(1)
    {
        sem_wait(&pSem2);
        printf("人脸检测!\n");
        sleep(1);
        sem_post(&pSem3);
    }
}

void *threadFunc3(void *argv)
{
    while(1)
    {   
        sem_wait(&pSem3);//0阻塞
        printf("人脸识别!\n");
        sleep(1);
        sem_post(&pSem1);
    }
}
int main()
{
    //初始化无名信号量
    sem_init(&pSem1,0,1);
    sem_init(&pSem2,0,0);
    sem_init(&pSem3,0,0);
   
    //1.创建线程ID号
    pthread_t thID1,thID2,thID3;
    
    pthread_create(&thID1,NULL,threadFunc1,NULL);
    pthread_create(&thID2,NULL,threadFunc2,NULL);
    pthread_create(&thID3,NULL,threadFunc3,NULL);
    
    //阻塞
    pthread_join(thID1,NULL);
    pthread_join(thID2,NULL);
    pthread_join(thID3,NULL);
    while (1)
    {
        //printf("主线程!\n");
        sleep(1);
    }
    return 0;
}

 (2)互斥

/*01_pthread.c*/

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
//定义一个临界资源
char buf[30];
//创建锁
pthread_mutex_t myMutex;

void *threadFunc1(void *argv)
{
    int i=0;
    pthread_mutex_lock(&myMutex);
    char *ptr=(char *)argv;
    while(*ptr)
    {
        buf[i]=*ptr;
        i++;
        ptr++;
        usleep(30);
    }
    buf[i]='\0';
    puts(buf);
}


int main(int argc, char const *argv[])
{
    char str[30]="123456789";
    char atr[30]="ABCDEFGHI";
    int ret=pthread_mutex_init(&myMutex,NULL);
    
    
    //创建进程ID号
    pthread_t thID1,thID2;
    pthread_create(&thID1,NULL,threadFunc1,str);
    pthread_create(&thID2,NULL,threadFunc1,atr);
    
    //等待
    pthread_join(thID1,NULL);
    pthread_join(thID2,NULL);

    //销毁锁
    pthread_mutexattr_destroy(&myMutex);
    return 0;
}

 

0.0 模板

名称(NAME)

        

概要(SYNOPSIS)

       

参数

       

       

返回值(RETURN)

        

.        

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小囧豆豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值