Explicación súper detallada del proceso C/C++ [Parte 2] (día de aprendizaje sistemático 07)

Tabla de contenido

Prefacio

1. Proceso del demonio

1. Concepto

2. El principio de creación del proceso de demonio (como se ve claramente en la imagen)

 3. Implementación del proceso demonio (bloque de código)

2. dup y dup2

1. Copiar el descriptor del archivo

2. Redirección de descriptores de archivos

3. Registro del sistema

1. Abra el registro

2. Escribe un mensaje en el registro.

3. Cierra el registro

4. Bloqueo de archivos

1. Concepto

2. Bloquear todo el archivo

El código de ejemplo es el siguiente: 

3. Bloquear un área determinada del archivo.

 El código de ejemplo es el siguiente:

5. Comunicación entre procesos

1. Clasificación

2. Tubería sin nombre

2.1 Principio de comunicación por tubería anónima

2.2 Uso

 El código de ejemplo es el siguiente:

Resumir


Prefacio

El blog anterior explicó en detalle la parte superior del proceso C / C ++, este blog continuará explicando y complementando el conocimiento sobre subprocesos.


1. Proceso del demonio

1. Concepto

(1) El proceso demonio,
    también conocido como proceso demonio, es un proceso de servicio en segundo plano en Linux.
    Es un proceso con una larga vida útil, generalmente independiente del terminal de control, y periódicamente realiza ciertas tareas o espera para manejar ciertos eventos que ocurren. El
    proceso demonio a menudo se inicia cuando el sistema se inicia y carga, y finaliza cuando el sistema está cerrado.
    Los sistemas Linux tienen muchos demonios, la mayoría de los servicios se implementan mediante demonios. 

(2) Terminal
    En Linux, la interfaz para que cada sistema se comunique con los usuarios se llama terminal. Cada proceso que comienza a ejecutarse desde este terminal se conectará a este terminal. Este terminal se llama terminal de control de estos procesos. Cuando el control terminal está Cuando está cerrado, los procesos correspondientes se cerrarán automáticamente.

El proceso demonio puede superar esta limitación: comienza a ejecutarse desde el momento en que se ejecuta y no sale hasta que se apaga todo el sistema.
Si desea que un proceso no se vea afectado por el usuario o el terminal u otros cambios, debe convertir este proceso en un proceso demonio. 

2. El principio de creación del proceso de demonio (como se ve claramente en la imagen)

 

 3. Implementación del proceso demonio (bloque de código)

void init_deamon(void)
{
    /*************** start ****************************/
    pid_t pid;
    int i,max_fd;

    //1,创建子进程
    if((pid = fork()) < 0){
        perror("fork");
        exit(1);
    }else if(pid > 0)
        exit(0);

    //2,创建新会话
    if(setsid() < 0){
        perror("setsid");
        exit(1);
    }
    //3,再创建子进程
    if((pid = fork()) < 0){
        perror("fork");
        exit(1);
    }else if(pid > 0)
        exit(0);

    //4,修改守护进程的工作目录
    chdir("/");

    //5,关闭进程父进程的所有的文件描述符
    max_fd = sysconf(_SC_OPEN_MAX);
    for (i = 0; i < max_fd;i++)
        close(i);
    //6,将标准输入,标准输出和标准错误重定向到/dev/null
    open("/dev/null",O_RDWR);
    dup(0);
    dup(0);

    //7,消除umask影响
    umask(0);
    /*************** end ****************************/
}

2. dup y dup2

1. Copiar el descriptor del archivo

int dup(int oldfd);
//Parámetro----El descriptor de archivo a copiar
//Valor de retorno----Éxito: nuevo descriptor de archivo, falla:-1

Ejemplo: 
int main(void)
{     char str[] = "hola mundo";     intfd1,fd2;


    fd1 = open("1.txt",O_RDWR|O_CREAT,0666);
    if(fd1 < 0){         perror("abrir");         salir(1);     }


    escribir(fd1,str,strlen(str));

    fd2 = dup(fd1); //Copiar la descripción del archivo fd1
    strcpy(str,"farsight");
    write(fd2,str,strlen(str));

    cerrar(fd1);


    devolver 0;
}      
 

2. Redirección de descriptores de archivos

int dup2(int oldfd, int newfd);
//Parámetro 1 --- Descriptor del archivo de destino
//Parámetro 2 --- Descriptor del archivo a redirigir
//Valor de retorno---- Éxito 0, error: -1

Ejemplo: 
int main(void)
{     char str[] = "hola mundo";     intfd1,fd2;


    fd1 = open("1.txt",O_RDWR|O_CREAT,0666);
    if(fd1 < 0){         perror("abrir");         salir(1);     }     fd2 = open("2.txt",O_RDWR|O_CREAT,0666);     if(fd1 < 0){         perror("abrir");         salir(1);     }







    escribir(fd1,str,strlen(str));

    dup2(fd1,fd2); //Redireccionar fd2 a fd1

    strcpy(str,"visión lejana");
    escribir(fd2,str,strlen(str));
    cerrar(fd1);


    devolver 0;
}

3. Registro del sistema

1. Abra el registro

#include <syslog.h>
void openlog(const char *ident, int option, int facility);
//Parámetro 1 ------ //Etiqueta de registro, personalizada, información de registro fácil de encontrar
//Parámetro 2 -- ---- Opciones:
                LOG_CONS Si el mensaje no se puede enviar al registro, enviarlo a la consola
                LOG_NDELAY Abrir el socket sin demora y enviar el mensaje
                LOG_NOWAIT Crear un proceso hijo y enviar el mensaje al registro sin bloquear
                LOG_PERROR Enviar el registro y enviarlo al error estándar al mismo tiempo Archivo
                LOG_PID Agregar el ID del proceso al mensaje
//Parámetro 3 ------ Tipo de proceso:
                    LOG_DAEMON proceso demonio
                    LOG_FTP proceso de servicio tfp
                    LOG_KERN proceso del kernel
                    LOG_LPR proceso de servicio de impresión
                    LOG_MAIL proceso de servicio de correo

Un ejemplo es el siguiente:
    openlog("mydaemon",LOG_PID,LOG_DAEMON);

2. Escribe un mensaje en el registro.

void syslog(int priority, const char *format, ...);
//Parámetro 1 ----- Prioridad del mensaje
               LOG_EMERG Error muy urgente
               LOG_ALERT Error que debe solucionarse inmediatamente
               LOG_CRIT Error crítico
               LOG_ERR Error general
               LOG_WARNING Advertencia
               LOG_NOTICE Mensajes que necesita atención
               LOG_INFO Mensaje normal
               LOG_DEBUG Mensaje de depuración
//Parámetro 2 -----El formato de escritura de mensajes en el registro
//Parámetros variables----- Parámetros variables similares a printf
Por ejemplo: 
    syslog(LOG_ERR,"fopen: % s",strerror(errno));
    
Ejecute la prueba:
     grep mydaemon /var/log/syslog -n
    203:Sep 26 23:36:26 ubuntu mydaemon[28968]: fopen:No existe tal archivo o directorio

3. Cierra el registro

 cierre nulo (nulo);

4. Bloqueo de archivos

1. Concepto

Para resolver el problema de exclusión mutua entre procesos, se introducen bloqueos de asesoramiento.

El uso del método de bloquear archivos en lugar de crear archivos
    requiere seguir el "acuerdo de caballeros"
    con bloqueos compartidos y bloqueos exclusivos
    para bloquear todo el archivo o bloquear una determinada parte del archivo (bloqueo de registros).

2. Bloquear todo el archivo

#include <sys/file.h>
int grey(int fd, int operación);
//Parámetro 1 ---- Descriptor de archivo
//Parámetro 2 ---- Tipo de bloqueo: LOCK_SH LOCK_EX LOCK_UN
//Valor de retorno - -- Éxito: 0, Fracaso: -1

El código de ejemplo es el siguiente: 

Código uno:

int main(int argc,char **argv)
{
    int fd;
    int i;

    if(argc != 2){
        fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
        exit(0);
    }

    if((fd = open(argv[1],O_RDWR)) < 0){
        perror("open");
        exit(1);
    }

    while(1){
        printf("等待获取锁\n");
        //获取互斥锁
        if(flock(fd,LOCK_EX) < 0){
            perror("flock");
            exit(1);
        }

        for(i = 0; i < 7; i++){
            printf("正在上厕所\n");
            sleep(1);
        }
        //释放锁
        if(flock(fd,LOCK_UN) < 0){
            perror("flock");
            exit(1);
        }
        printf("上完厕所出来了....\n");
        sleep(1);
    }
    return 0;
}
 

Código dos:

int main(int argc,char **argv)
{
    int fd;
    int i;

    if(argc != 2){
        fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
        exit(0);
    }

    if((fd = open(argv[1],O_RDWR)) < 0){
        perror("open");
        exit(1);
    }

    while(1){
        printf("等待着上厕所\n");
        //获取互斥锁
        if(flock(fd,LOCK_EX) < 0){
            perror("flock");
            exit(1);
        }
        for(i = 0; i < 7; i++){
            printf("正在上厕所...\n");
            sleep(1);
        }
        //释放锁
        if(flock(fd,LOCK_UN) < 0){
            perror("flock");
            exit(1);
        }
        printf("上完厕所!\n");
        sleep(1);
    }
    return 0;
}

3. Bloquear un área determinada del archivo.

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );

 estructura rebaño {        short l_type; /* Tipo de bloqueo: F_RDLCK, F_WRLCK, F_UNLCK */        short l_whence; /* Cómo interpretar l_start:                            SEEK_SET, SEEK_CUR, SEEK_END */        off_t l_start; /* Desplazamiento inicial para bloqueo */        off_t l_len; /* Número de bytes a bloquear */        pid_t l_pid; /* PID del proceso que bloquea nuestro bloqueo                            (establecido por F_GETLK y F_OFD_GETLK) */    };







 El código de ejemplo es el siguiente:

//定义锁的结构体--设置锁的区域
     struct flock fl = {
         .l_whence = SEEK_SET,
        .l_start = 100,
        .l_len  = 1024,
    };

    while(1){
        printf("等待获取锁\n");
        //获取互斥锁
        fl.l_type = F_WRLCK;   //设置锁的类型
        if(fcntl(fd,F_SETLKW,&fl) < 0){
            perror("flock");
            exit(1);
        }

        for(i = 0; i < 7; i++){
            printf("正在上厕所\n");
            sleep(1);
        }
        //释放锁
        fl.l_type = F_UNLCK;    //解锁
        if(fcntl(fd,F_SETLK,&fl) < 0){
            perror("flock");
            exit(1);
        }
        printf("上完厕所出来了....\n");
        sleep(1);
    }

5. Comunicación entre procesos

1. Clasificación

 La comunicación entre procesos en Linux se divide en tres categorías:
(1) Comunicación temprana entre procesos canalización
    desconocida
    con nombre (con nombre)
    señal de canalización (2)     cola de mensajes
IPC del sistema V semáforo     de memoria compartida     (volumen) (3) socket de dominio Unix



2. Tubería sin nombre

2.1 Principio de comunicación por tubería anónima

2.2 Uso

#include <unistd.h>
int pipe(int pipefd[2]);
//Parámetros----Matriz para guardar los descriptores de archivos en ambos extremos de la tubería
//Valor de retorno---Éxito: 0, Fallo: - 1

 El código de ejemplo es el siguiente:
int main(void)
{
    int fd[2];
    pid_t pid;
    char buf[100];

    //创建无名管道
    if(pipe(fd) < 0){   //pipe()会在内核中创建无名管道,然后将管道两端的文件描述符返回给当前进程
        perror("pipe");
        exit(1);
    }

    //创建子进程
    if((pid = fork()) < 0){
        perror("fork");
        exit(1);
    }else if(!pid){  //子进程执行:从键盘获取字符串,写到管道中
        close(fd[0]);  //关闭读端
        while(1){
            fgets(buf,sizeof(buf),stdin);
            write(fd[1],buf,strlen(buf));   //向管道中写数据
        }
    }else{  //父进程执行:从管道读数据,打印到屏幕上
        close(fd[1]); //关闭写端
        while(1){
           if(read(fd[0],buf,sizeof(buf)) < 0){
                perror("read");
                exit(1);
           }
           printf("%s",buf);
        }
    }

    return 0;
}


Resumir

        Este artículo explica y complementa el proceso con gran detalle. ¡Espero que pueda ayudar a todos!

        En el futuro, les mostraré conocimientos básicos más importantes sobre el lenguaje integrado y C. ¡Gracias por apoyar a Lazy King!

       Espero que este blog pueda brindar ayuda a todos mis amigos. Finalmente, los amigos que han sido invitados por Lazy King dejarán sus valiosos comentarios y atención. ¡Gracias!

Supongo que te gusta

Origin blog.csdn.net/weixin_58070962/article/details/133465184
Recomendado
Clasificación