Super detaillierte Erklärung des C/C++-Prozesses [Teil 2] (systematischer Lerntag07)

Inhaltsverzeichnis

Vorwort

1. Daemon-Prozess

1. Konzept

2. Das Prinzip der Daemon-Prozesserstellung (wie im Bild deutlich sichtbar)

 3. Implementierung des Daemon-Prozesses (Codeblock)

2. dup und dup2

1. Dateideskriptor kopieren

2. Dateideskriptorumleitung

3. Systemprotokoll

1. Öffnen Sie das Protokoll

2. Schreiben Sie eine Nachricht in das Protokoll

3. Schließen Sie das Protokoll

4. Dateisperre

1. Konzept

2. Sperren Sie die gesamte Datei

Der Beispielcode lautet wie folgt: 

3. Sperren Sie einen bestimmten Bereich der Datei

 Der Beispielcode lautet wie folgt:

5. Kommunikation zwischen Prozessen

1. Klassifizierung

2. Unbenannte Pipe

2.1 Prinzip der anonymen Pipe-Kommunikation

2.2 Nutzung

 Der Beispielcode lautet wie folgt:

Zusammenfassen


Vorwort

Im vorherigen Blog wurde der obere Teil des C/C++-Prozesses ausführlich erläutert. In diesem Blog wird das Wissen über Threads weiter erläutert und ergänzt.


1. Daemon-Prozess

1. Konzept

(1) Der Daemon-Prozess,
    auch Daemon-Prozess genannt, ist ein Hintergrunddienstprozess unter Linux.
    Es handelt sich um einen Prozess mit langer Lebensdauer, der normalerweise unabhängig vom steuernden Terminal ist und regelmäßig bestimmte Aufgaben ausführt oder auf die Verarbeitung bestimmter auftretender Ereignisse wartet. Der Daemon-
    Prozess wird häufig gestartet, wenn das System gebootet und geladen wird, und beendet, wenn das System gestartet wird wird heruntergefahren.
    Linux-Systeme haben viele Daemons, die meisten Dienste werden mithilfe von Daemons implementiert 

(2) Terminal
    Unter Linux wird die Schnittstelle jedes Systems zur Kommunikation mit Benutzern als Terminal bezeichnet. Jeder Prozess, der von diesem Terminal aus ausgeführt wird, wird an dieses Terminal angeschlossen. Dieses Terminal wird als Steuerterminal dieser Prozesse bezeichnet. Wenn die Steuerung Terminal ist Wenn es geschlossen ist, werden die entsprechenden Prozesse automatisch geschlossen.

Der Daemon-Prozess kann diese Einschränkung durchbrechen. Er startet ab dem Moment seiner Ausführung und wird erst beendet, wenn das gesamte System heruntergefahren wird.
Wenn Sie möchten, dass ein Prozess nicht von Benutzer- oder Terminal- oder anderen Änderungen betroffen ist, müssen Sie diesen Prozess in einen Daemon-Prozess umwandeln. 

2. Das Prinzip der Daemon-Prozesserstellung (wie im Bild deutlich sichtbar)

 

 3. Implementierung des Daemon-Prozesses (Codeblock)

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 und dup2

1. Dateideskriptor kopieren

int dup(int oldfd);
//Parameter----Der zu kopierende Dateideskriptor
//Rückgabewert----Erfolg: Neuer Dateideskriptor, Fehler:-1

Beispiel: 
int main(void)
{     char str[] = "hello world";     int fd1,fd2;


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


    write(fd1,str,strlen(str));

    fd2 = dup(fd1); //Dateibeschreibung kopieren fd1
    strcpy(str,"farsight");
    write(fd2,str,strlen(str));

    schließen(fd1);


    0 zurückgeben;
}      
 

2. Dateideskriptorumleitung

int dup2(int oldfd, int newfd);
//Parameter 1 --- Zieldateideskriptor
//Parameter 2 --- Dateideskriptor, der umgeleitet werden soll
//Rückgabewert---- Erfolg 0, Fehler: -1

Beispiel: 
int main(void)
{     char str[] = "hello world";     int fd1,fd2;


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







    write(fd1,str,strlen(str));

    dup2(fd1,fd2); //fd2 zu fd1 umleiten

    strcpy(str,"farsight");
    write(fd2,str,strlen(str));
    schließen(fd1);


    0 zurückgeben;
}

3. Systemprotokoll

1. Öffnen Sie das Protokoll

#include <syslog.h>
void openlog(const char *ident, int option, int Facilities);
//Parameter 1 ------ //Protokollbezeichnung, angepasst, leicht zu findende Protokollinformationen
//Parameter 2 -- ---- Optionen:
                LOG_CONS Wenn die Nachricht nicht an das Protokoll gesendet werden kann, senden Sie sie an die Konsole.
                LOG_NDELAY Öffnen Sie den Socket ohne Verzögerung und senden Sie die Nachricht.
                LOG_NOWAIT Erstellen Sie einen untergeordneten Prozess und senden Sie die Nachricht an das Protokoll, ohne sie zu blockieren.
                LOG_PERROR Senden Sie das Protokoll und gleichzeitig an den Standardfehler senden Datei
                LOG_PID Fügen Sie der Nachricht die Prozess-ID hinzu
//Parameter 3 ------ Prozesstyp:
                    LOG_DAEMON Daemon-Prozess
                    LOG_FTP TFP-Dienstprozess
                    LOG_KERN Kernelprozess
                    LOG_LPR Druckdienstprozess
                    LOG_MAIL Mail-Dienstprozess

Ein Beispiel lautet wie folgt:
    openlog("mydaemon",LOG_PID,LOG_DAEMON);

2. Schreiben Sie eine Nachricht in das Protokoll

void syslog(int Priority, const char *format, ...);
//Parameter 1 ----- Nachrichtenpriorität
               LOG_EMERG Sehr dringender Fehler
               LOG_ALERT Fehler, der sofort behandelt werden muss
               LOG_CRIT Kritischer Fehler
               LOG_ERR Allgemeiner Fehler
               LOG_WARNING Warnung
               LOG_NOTICE Meldet, dass brauche Aufmerksamkeit
               LOG_INFO Normale Nachricht
               LOG_DEBUG Debug-Nachricht
//Parameter 2 -----Das Format zum Schreiben von Nachrichten in das Protokoll
//Variable Parameter----- Variable Parameter ähnlich wie printf
Zum Beispiel: 
    syslog(LOG_ERR,"fopen: % s",strerror(errno));
    
Führen Sie den Test aus:
     grep mydaemon /var/log/syslog -n
    203:Sep 26 23:36:26 ubuntu mydaemon[28968]: fopen:Keine solche Datei oder kein solches Verzeichnis

3. Schließen Sie das Protokoll

 void closelog(void);

4. Dateisperre

1. Konzept

Um das Problem des gegenseitigen Ausschlusses zwischen Prozessen zu lösen, werden Beratungssperren eingeführt

Die Verwendung der Methode zum Sperren von Dateien anstelle der Erstellung von Dateien
    erfordert die Einhaltung der „Gentleman's Agreement“
    gemeinsamer Sperren und exklusiver Sperren
    , um die gesamte Datei oder einen bestimmten Teil der Datei zu sperren (Datensatzsperre).

2. Sperren Sie die gesamte Datei

#include <sys/file.h>
int flock(int fd, int operation);
//Parameter 1 ---- Dateideskriptor
//Parameter 2 ---- Sperrtyp: LOCK_SH LOCK_EX LOCK_UN
//Rückgabewert- -- Erfolg: 0, Fehler: -1

Der Beispielcode lautet wie folgt: 

Code eins:

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

Code zwei:

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. Sperren Sie einen bestimmten Bereich der Datei

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

 struct flock {        short l_type; /* Art der Sperre: F_RDLCK, F_WRLCK, F_UNLCK */        short l_whence; /* So interpretieren Sie l_start:                            SEEK_SET, SEEK_CUR, SEEK_END */        off_t l_start; /* Startoffset für Sperre */        off_t l_len; /* Anzahl der zu sperrenden Bytes */        pid_t l_pid; /* PID des Prozesses, der unsere Sperre blockiert                            (gesetzt durch F_GETLK und F_OFD_GETLK) */    };







 Der Beispielcode lautet wie folgt:

//定义锁的结构体--设置锁的区域
     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. Kommunikation zwischen Prozessen

1. Klassifizierung

 Die Kommunikation zwischen Prozessen unter Linux ist in drei Kategorien unterteilt:
(1) Frühe Kommunikation zwischen Prozessen,
    unbekanntes Pipe-
    Name (benanntes) Pipe-
    Signal
(2) System V IPC-
    Nachrichtenwarteschlange,
    gemeinsam genutztes
    Speichersemaphor (Volume),
(3) Unix-Domänen-Socket

2. Unbenannte Pipe

2.1 Prinzip der anonymen Pipe-Kommunikation

2.2 Nutzung

#include <unistd.h>
int pipe(int pipefd[2]);
//Parameter----Array zum Speichern der Dateideskriptoren an beiden Enden der Pipe
//Rückgabewert---Erfolg: 0, Fehler: - 1

 Der Beispielcode lautet wie folgt:
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;
}


Zusammenfassen

        Dieser Artikel erklärt und ergänzt den Prozess ausführlich. Ich hoffe, er kann allen helfen!

        In Zukunft werde ich Ihnen weitere wichtige Grundkenntnisse über eingebettete und C-Sprache zeigen. Vielen Dank für die Unterstützung von Lazy King!

       Ich hoffe, dass dieser Blog allen meinen Freunden helfen kann. Schließlich werden Freunde, die von Lazy King eingeladen wurden, Ihre wertvollen Kommentare und Ihre Aufmerksamkeit hinterlassen. Vielen Dank!

Ich denke du magst

Origin blog.csdn.net/weixin_58070962/article/details/133465184
Empfohlen
Rangfolge