C语言详解分析进程控制中进程终止的实现

2022-08-29 12:07:24
目录
进程退出的形式进程退出的几种方法

进程退出的形式

进程退出的几种情况

    正常退出(自愿,代码运行完其结果正确)错误退出(自愿,代码运行完其结果不正确)异常退出(非自愿,代码异常直接终止)被其他进程终止(非自愿)

    自愿退出会返回一个退出码,由父进程接收。

    在Linux上可以使用命令echo>显示最近一次退出的进程返回的退出码

      //现有如下代码,源文件名为mycode.c
     # include <stdio.h>
     int main(void)
     {
       printf("i am testing\n");                                                                                                                                     
       return 0;
     }

    运行以上代码……

    使用命令echo $?显示退出码

    正常退出的退出码为0,错误退出的退出码为非0

    退出码反应了进程退出的原因。所以有必要知道这些退出码究竟代表着什么。

    strerror()函数的作用就是以字符的形式返回退出码。

    //所在头文件
    <string.h>
    //函数原型
    char* strerror(int errNum);
    
    //可以使用下面代码查看退出码对应的信息
     # include <stdio.h>
     # include <string.h>
     int main(void)
     {
       for(int i = 0; i < 135; i++)                                                                                                                                  
       {
         printf("%d: %s\n", i, strerror(i));
       }
       return 0;
     }

    Linux系统上一共有134个退出码,退出码“134”就已经不认识它了。

    0: Success
    1: Operation not permitted
    2: No such file or directory
    3: No such process
    4: Interrupted system call
    5: Input/output error
    6: No such device or address
    7: Argument list too long
    8: Exec format error
    9: Bad file descriptor
    10: No child processes
    11: Resource temporarily unavailable
    12: Cannot allocate memory
    13: Permission denied
    14: Bad address
    15: Block device required
    16: Device or resource busy
    17: File exists
    18: Invalid cross-device link
    19: No such device
    20: Not a directory
    21: Is a directory
    22: Invalid argument
    23: Too many open files in system
    24: Too many open files
    25: Inappropriate ioctl for device
    26: Text file busy
    27: File too large
    28: No space left on device
    29: Illegal seek
    30: Read-only file system
    31: Too many links
    32: Broken pipe
    33: Numerical argument out of domain
    34: Numerical result out of range
    35: Resource deadlock avoided
    36: File name too long
    37: No locks available
    38: Function not implemented
    39: Directory not empty
    40: Too many levels of symbolic links
    41: Unknown error 41
    42: No message of desired type
    43: Identifier removed
    44: Channel number out of range
    45: Level 2 not synchronized
    46: Level 3 halted
    47: Level 3 reset
    48: Link number out of range
    49: Protocol driver not attached
    50: No CSI structure available
    51: Level 2 halted
    52: Invalid exchange
    53: Invalid request descriptor
    54: Exchange full
    55: No anode
    56: Invalid request code
    57: Invalid slot
    58: Unknown error 58
    59: Bad font file format
    60: Device not a stream
    61: No data available
    62: Timer expired
    63: Out of streams resources
    64: Machine is not on the network
    65: Package not installed
    66: Object is remote
    67: Link has been severed
    68: Advertise error
    69: Srmount error
    70: Communication error on send
    71: Protocol error
    72: Multihop attempted
    73: RFS specific error
    74: Bad message
    75: Value too large for defined data type
    76: Name not unique on network
    77: File descriptor in bad state
    78: Remote address changed
    79: Can not access a needed shared library
    80: Accessing a corrupted shared library
    81: .lib section in a.out corrupted
    82: Attempting to link in too many shared libraries
    83: Cannot exec a shared library directly
    84: Invalid or incomplete multibyte or wide character
    85: Interrupted system call should be restarted
    86: Streams pipe error
    87: Too many users
    88: Socket operation on non-socket
    89: Destination address required
    90: Message too long
    91: Protocol wrong type for socket
    92: Protocol not available
    93: Protocol not supported
    94: Socket type not supported
    95: Operation not supported
    96: Protocol family not supported
    97: Address family not supported by protocol
    98: Address already in use
    99: Cannot assign requested address
    100: Network is down
    101: Network is unreachable
    102: Network dropped connection on reset
    103: Software caused connection abort
    104: Connection reset by peer
    105: No buffer space available
    106: Transport endpoint is already connected
    107: Transport endpoint is not connected
    108: Cannot send after transport endpoint shutdown
    109: Too many references: cannot splice
    110: Connection timed out
    111: Connection refused
    112: Host is down
    113: No route to host
    114: Operation already in progress
    115: Operation now in progress
    116: Stale file handle
    117: Structure needs cleaning
    118: Not a XENIX named type file
    119: No XENIX semaphores available
    120: Is a named type file
    121: Remote I/O error
    122: Disk quota exceeded
    123: No medium found
    124: Wrong medium type
    125: Operation canceled
    126: Required key not available
    127: Key has expired
    128: Key has been revoked
    129: Key was rejected by service
    130: Owner died
    131: State not recoverable
    132: Operation not possible due to RF-kill
    133: Memory page has hardware error
    134: Unknown error 134

    Linux上一切皆为文件,指令也是一个文件,当使用不存在的指令时,就会出现报错信息。

    其退出码为2,退出码2代表的含义为: No such file or directory(没有这样的文件或目录)

    进程退出的几种方法

    正常终止的3种方法:

      main函数返回调用exit调用_exit

      最常见的进程终止莫过于main函数返回了!需要注意main函数中返回才是进程退出,而非main函数返回并不能正常终止进程,只是函数返回。

      【调用exit】

      //所在头文件
       #include <stdlib.h>
       //exit函数原型
       void exit(int status);
      

      exit函数是语言层面的函数,是对系统调用函数_exit的封装。

      它可以在main函数中调用,也可以在非main函数中调用,都可以达到终止进程的目的。

      C标准还规定了两个宏EXIT_SUCCESS和EXIT_FAILURE可以作为exit的参数,用来指示这个进程是正常退出还是错误退出。

       # include <stdio.h>
       # include <string.h>
       # include <stdlib.h>
       int main(void)
       {
         printf("i am testing\n");
         exit(EXIT_SUCCESS);                                                                                                                                           
         return 0;
       }

       # include <stdio.h>
       # include <string.h>
       # include <stdlib.h>
       int main(void)
       {
         printf("i am testing\n");
         exit(EXIT_FAILURE);     //修改exit函数的参数                                                                                                                                      
         return 0;
       }

      【调用_exit函数】

      //所在头文件
      #include <unistd.h>
      //_exit函数原型
      void _exit(int status);
      

      _exit是系统调用函数。_exit函数的本质就是调用了系统调用函数_exit。

      exit函数封装了系统调用_exit,exit函数还做了其他的事情。

       # include <stdio.h>
       # include <string.h>
       # include <stdlib.h>
       # include <unistd.h>
       int main(void)
       {
         printf("i am testing"); //没有“\n”
         sleep(2);
         exit(EXIT_SUCCESS);
         return 0;                                                                                                                                                     
       }

      代码运行的现象:休眠2秒后,在屏幕上打印“i am testing”.

      因此,可以看出,exit函数会冲刷缓冲区……

      现在换做_exit函数来终止进程。

       # include <stdio.h>
       # include <string.h>
       # include <stdlib.h>
       # include <unistd.h>
       int main(void)
       {
         printf("i am testing"); //没有“\n”
         sleep(2);
         _exit(EXIT_SUCCESS);
         return 0;                                                                                                                                                     
       }

      代码运行的现象:休眠两秒后,并没有在屏幕上显示预期的“i am testing”,就终止进程了。

      因此可看出,_exit函数并不会冲刷缓冲区……

      实际上,_exit系统调用函数只是简单地终止了进程,并不会做其他的工作。而exit函数在调用_exit函数之前还会做一些其他的工作:

        执行用户定义的清理函数冲刷缓冲区,关闭所有的流等。调用_exit函数

        main函数返回,本质上是把返回值作为参数传给exit函数,最后还是调用exit函数。

        到此这篇关于C语言详解分析进程控制中进程终止的实现的文章就介绍到这了,更多相关C语言进程终止内容请搜索易采站长站以前的文章或继续浏览下面的相关文章希望大家以后多多支持易采站长站!