Linux 进程状态环境变量

news/2024/5/9 22:50:54

 

目录

一、操作系统的进程状态 

二、Linux内核的进程状态    

1、S、R状态

2、前后台进程 

3、可中断睡眠(S>>T状态)

4、D状态(不可中断睡眠)

5、僵尸进程(Z状态)

三、孤儿进程

四、优先级 

1、概念 

2、PRI and NI

3、查看进程优先级

五、其他概念

六、环境变量

1、基本概念

2、常见环境变量

3、查看环境变量

4、环境变量的组织方式

5、环境变量具有全局属性

6、命令行参数 


一、操作系统的进程状态 

  • 运行态:task_struct结构体在运行队列中排队,就叫做运行态。
  • 阻塞:等待非CPU资源就绪就是阻塞状态 。
  • 挂起:当内存不足的时候,OS通过适当的置换进程的代码和数据到磁盘(换出到磁盘的SWAP分区),进程的状态就叫做挂起。

二、Linux内核的进程状态    

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

在Linux内核源代码中,进程状态通过一个特殊的“位图”数组task_state_array来定义,这个数组使用不同的数字来标识进程的不同状态。每个状态都对应一个特定的值,这些值通过位操作来测试组合状态。下面是对各个状态的解释和它们在实际中的含义:

  • R (运行状态): 对应运行状态,表示进程可能正在运行或者在运行队列中等待。这并不意味着进程一定在CPU上执行,但它是准备执行的状态。

  • S (睡眠状态,可中断睡眠): 也是就对应阻塞状态,进程在等待某个事件完成。这种状态通常是可中断的,意味着进程可以被唤醒来响应某些事件。

  • D (磁盘休眠状态): 也称为不可中断睡眠状态,不可以被被动唤醒,进程在此状态下通常等待I/O操作的完成。在这个状态下的进程不能被信号唤醒。

  • T (停止状态,单纯暂停,调试中体现): 进程被SIGSTOP信号停止。这种状态下的进程可以通过SIGCONT信号被重新唤醒继续执行。(kill -19 +id>>暂停,kil -18 +id>>恢复)

  • t (追踪暂停状态): 这是一种特殊的停止状态,用于调试目的,进程在被追踪或调试时可能会进入这个状态。

  • X (死亡状态,意味着当前我的资源可以被回收,瞬时性状态难以观察): 表示进程已经结束,但仍在等待父进程处理其退出状态。这是一个临时状态,通常不会出现在任务列表中。

  • Z (僵尸状态,一个进程已经退出,但是还不允许被OS释放,处于一个被检测的状态): 进程已经结束,但其父进程尚未读取其退出状态。在父进程读取了子进程的退出状态后,子进程的资源将被释放。

1、S、R状态

我们观察下面程序的运行状态 :

#include <stdio.h>int main()
{int a=0;while(1){}return 0;
}

 有printf打印到显示器就是访问外设的过程,可能打印时需要等待外设一会,与在就绪队列的时间相比,进程大部分时间在阻塞队列,小部分时间在运行队列,所以显示S状态。

如果去掉输出语句会变为R状态。

 加入scanf语句运行后,程序一直在等待外设输入,状态为R。

#include <stdio.h>int main()
{int a=0;scanf("%d",&a);while(1){}return 0;
}

2、前后台进程 

观察上面进程的状态可以发现,状态标识符后有一个加号,代表这个进程是前台进程。

前台进程一启动,输入命令就没用了,同时前台进程可以被ctrl+c中止。前台进程占用你的bash(命令行解释器)对话框,所以前台进程运行时,命令行解释器无法解释命令了。

如何将程序运行在后台呢? 

#include <stdio.h>int main()
{int a=0;while(1){}return 0;
}

 运行时在最后加一个&可以使程序运行在后台,这时我们可以继续输入命令并成功执行。

[hbr@VM-16-9-centos state]$ ./mytest &
[1] 7667
[hbr@VM-16-9-centos state]$ ls
Makefile  mytest  mytest.c  test1.c  test.c
[hbr@VM-16-9-centos state]$ ^C
[hbr@VM-16-9-centos state]$ ^C
[hbr@VM-16-9-centos state]$ kill -9 7667
[1]+  Killed                  ./mytest

 ctrl+c已经不能结束后台程序,可以使用kil -9 id结束程序。

在Linux中,进程可以运行在前台或后台模式。这两种模式主要影响进程与终端的交互方式,以及如何控制和管理进程。

前台进程

  • 交互性:前台进程直接与用户的终端会话关联,用户可以直接与之交互。
  • 控制:当一个进程在前台运行时,它可以接收来自终端的输入和信号。例如,你可以使用Ctrl+C来中断一个正在前台运行的进程。
  • 限制:在一个时间点上,只能有一个前台进程组与终端交互。

后台进程

  • 运行方式:后台进程在后台执行,不占用终端,允许用户在同一终端中继续执行其他命令。
  • 启动:通常通过在命令末尾添加&符号来启动后台进程。例如,some_command &会将some_command作为后台进程启动。
  • 控制:后台进程不会接收来自终端的输入,但它们仍然可以向终端输出信息。如果需要,可以使用fg命令将后台进程切换到前台,或使用bg命令来控制已停止的后台进程继续运行。
  • 通知:当后台进程结束时,终端会显示该进程的退出状态。

管理

  • 查看:可以使用jobs命令查看当前会话中的后台进程列表。
  • 控制fg命令可以将后台进程带到前台,bg命令可以让停止的进程在后台继续运行。

3、可中断睡眠(S>>T状态)

我们先让程序通过sleep进入睡眠状态 。

#include <stdio.h>
#include <unistd.h>
int main()
{sleep(1000);int a=0;while(1){}return 0;
}

 使用kil -19 +id使程序暂停,我们发现程序由S状态进入T暂停状态,还可以使用-18号信号使进程恢复到S状态,这就是可中断睡眠。

4、D状态(不可中断睡眠)

 D状态与磁盘相关,当服务器内存压力过大,操作系统会通过一定手段杀掉一些进程,这样起到节省空间的作用,当进程正在等待磁盘I/O操作,为了保证内存压力过大时,未收到I/O操作完成信号的这个进程不被杀掉,该进程被设置为D(不可中断睡眠)状态。

  • 在Linux系统中,进程的状态包括了多种状态,其中"D"状态通常表示进程处于不可中断的睡眠状态(Uninterruptible Sleep)。这种状态通常与磁盘I/O操作相关,当进程在等待磁盘I/O操作完成时,会进入"D"状态。
  • 举例来讲,假设有一个进程正在进行文件读取操作,但是由于文件所在的磁盘速度较慢或者磁盘负载较高,导致读取操作需要较长时间才能完成。在这种情况下,该进程可能会进入"D"状态,等待磁盘I/O操作完成。
  • 当进程处于"D"状态时,它是无法被中断的,即使收到信号也无法立即响应。这是因为进程在等待磁盘I/O操作完成时,必须等待磁盘响应,无法立即终止或切换到其他状态。只有当磁盘I/O操作完成后,进程才能从"D"状态恢复到可运行状态。

5、僵尸进程(Z状态)

  • 僵死状态是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用) 没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。
  • 当一个进程结束并成为僵尸进程时,其代码和数据空间被操作系统释放,但进程的 PCB 数据结构仍然存在。
  • 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
  • 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。

三、孤儿进程

概念:

  • 当父进程退出后,子进程仍在运行的情况下,子进程会成为孤儿进程。孤儿进程之所以会被“领养”,是因为它们需要一个新的父进程来处理它们的退出状态和释放资源。
  • 通常情况下,孤儿进程会被系统中的一个特殊进程所领养,这个特殊进程的进程 ID 为1,称为 init 进程,或者在一些系统中称为 systemd。init 进程是系统启动后的第一个进程,它负责初始化系统,并在需要时处理孤儿进程。
  • 孤儿进程被领养的原因在于父进程可能在子进程退出之前就已经退出了,这样的情况下,孤儿进程的退出状态和资源释放就无法由父进程来处理。因此,init 进程或者系统中的其他特殊进程会接管这些孤儿进程,负责它们的清理工作,防止资源泄露和系统资源的浪费。

通过下面代码观察一下孤儿进程 。

我们通过fork()创建了一个子进程。fork()函数调用成功后,会创建一个新的进程(子进程),这个新进程几乎是父进程的副本。在子进程中,fork()返回0,而在父进程中,它返回子进程的PID。 

  •  父进程在打印五次消息后结束运行,但子进程因为while(1)循环,会无限期地继续运行,打印"hello"消息。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t id=fork();if(id==0){while(1){printf("hello\n");}}else{int n=5;while(n){printf("I am father : %d\n",n--);sleep(1);}}return 0;
}

 五秒后父进程退出,可以观察到只剩子进程,这时的子进程就是孤儿进程

未来子进程退出的时候,父进程早已不在,需要领养进程来进行回收。 

所以孤儿进程会被系统的init进程(通常是systemdinit)接管。接管后,孤儿进程的父进程ID(PPID)会被设置为1,这是init进程的PID。

  • 在这种情况下,子进程不再有与父进程相同的终端控制,因此它可能会成为后台进程,不再受终端的前台控制。这解释了为什么父进程终止后,子进程输出由前台变为后台。
  • 要终止后台持续输出"Hello"的子进程,可以右侧窗口输入:使用kill -9来发送SIGKILL信号,这是一个强制终止进程的信号:kill -9 21224(右侧持续输出时也可以读取到我们输入的命令)。

四、优先级 

1、概念 

为什么要有优先级?

  • 就是因为CPU是有限的!进程太多,需要通过某种方式竞争资源(CPU)。

什么是优先级?

  • 优先级是调度器的主要参考,放入运行队列拿出运行队列,是调度的重要指标。
  • 确认是谁应该先获得某种资源,谁后获得资源。

我们是可以用一些数据表明优先级的!

  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行
  • NI :代表这个进程的nice值

2、PRI and NI

  • PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
  • 那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值 PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
  • 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行 ,所以,调整进程优先级,在Linux下,就是调整进程nice值
  • nice其取值范围是-20至19,一共40个级别。通过调整 nice 值,可以提高系统的公平性和响应性。合理地分配 CPU 时间片可以确保不同类型的任务都能够得到适当的处理,从而提高系统的整体性能和用户体验。
  • 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。 可以理解nice值是进程优先级的修正修正数据

3、查看进程优先级

用top命令更改已存在进程的nice:
  • top 进入top后按“r”–>输入进程PID–>输入nice值

五、其他概念

竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。

  • 例如父子进程就具有独立性,这也是为什么bash运行命令需要创建子进程。

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。

并发: 指在一段时间内,多个进程在单个 CPU 下交替执行,通过进程切换的方式,使得每个进程都得以推进。这种情况下,虽然每个进程并不是同时执行的,但由于进程切换的频繁发生,给人的感觉就像它们在同时运行一样。

  • 时间片是操作系统调度算法中的一种机制,它将 CPU 的执行时间划分为多个时间片,每个进程被分配一个时间片,在该时间片内运行。一旦时间片耗尽,操作系统会进行进程切换,将 CPU 分配给下一个等待执行的进程。这样,每个进程都能在一定的时间内执行,从而实现了并发执行的效果。

  • 在时间片轮转调度算法中,所有进程轮流执行,每个进程被分配的时间片长度相同,这样可以确保每个进程都有机会执行。当一个进程的时间片用尽时,操作系统会将 CPU 分配给下一个就绪的进程,这种切换的频率非常快,给人的感觉就是多个进程同时在执行,实现了并发。

  • 因此,通过时间片和进程切换的结合,操作系统可以实现多个进程在单个 CPU 下的并发执行,提高了系统的资源利用率和响应性。

进程切换:

  • 在计算机系统中,每个进程在执行过程中都会有自己的上下文数据,其中包括寄存器的内容、内存映射、程序计数器等。这些上下文数据可以被视为进程的状态快照,用于保存进程执行时的环境和状态信息。
  • 当进程A正在运行时,CPU内的寄存器中保存的是进程A的临时数据,这些数据构成了进程A的上下文。每个进程都有自己的上下文数据,包括寄存器状态、程序计数器、栈指针等信息。
  • 尽管CPU内的寄存器只有一份,但是上下文数据可以有多份,每份对应不同的进程。这意味着在进行进程切换时,操作系统需要保存当前进程的上下文数据,并加载下一个进程的上下文数据,以确保进程切换后能够正确继续执行。
  • 上下文数据绝对不能被丢弃,因为它包含了进程执行的关键信息,丢失上下文数据将导致进程无法正确恢复执行状态。当进程A被暂时切换出去时,它需要携带自己的上下文数据,这样下次回来时就能够恢复到之前的执行状态,继续按照之前的逻辑向后运行,就好像没有被中断过一样。这种保存和恢复上下文数据的机制确保了操作系统能够有效地管理多个进程并实现多任务处理。

六、环境变量

1、基本概念

环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,

  • 比如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,
  • 原因就是有相关环境变量帮助编译器进行查找。
  • 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性

2、常见环境变量

  • PATH : 指定命令的搜索路径
  • HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
  • SHELL : 当前Shell,它的值通常是/bin/bash。

系统命令可以直接运行,我自己写的程序必须带路径!,如果不想带呢? 如果我想让和运行普通命令一样,我们可以使用export PATH=$PATH:地址 将这个地址添加到搜索路径中。这次我们可以直接使用myproc运行程序。

3、查看环境变量

echo $NAME //NAME:你的环境变量名称
和环境变量相关的命令
1. echo: 显示某个环境变量值
2. export: 设置一个新的环境变量
3. env: 显示所有环境变量
4. unset: 清除环境变量
5. set: 显示本地定义的shell变量和环境变量
我们使用程序为环境变量标上序号进行打印输出env。
#include <stdio.h>int main(int argc,char* argv[],char *env[])
{int i=0;for(;env[i];i++){printf("env[%d]:%s\n",i,env[i]);}return 0;
}
还可以通过第三方变量environ获取(效果与env等同),libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明。
#include <stdio.h>
int main(int argc, char *argv[])
{extern char **environ;int i = 0;for(; environ[i]; i++){printf("%s\n", environ[i]);}return 0;
}
[hbr@VM-16-9-centos environment_variable]$ ./mytest 
env[0]:XDG_SESSION_ID=208189
env[1]:HOSTNAME=VM-16-9-centos
env[2]:TERM=xterm
env[3]:SHELL=/bin/bash
env[4]:HISTSIZE=3000
env[5]:SSH_CLIENT=42.84.233.50 30407 22
env[6]:SSH_TTY=/dev/pts/0
env[7]:USER=hbr
env[8]:LD_LIBRARY_PATH=:/home/hbr/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
env[9]:LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
env[10]:MAIL=/var/spool/mail/hbr
env[11]:PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/hbr/.local/bin:/home/hbr/bin
env[12]:PWD=/home/hbr/linux/environment_variable
env[13]:LANG=en_US.UTF-8
env[14]:SHLVL=1
env[15]:HOME=/home/hbr
env[16]:LOGNAME=hbr
env[17]:SSH_CONNECTION=42.84.233.50 30407 10.0.16.9 22
env[18]:LESSOPEN=||/usr/bin/lesspipe.sh %s
env[19]:PROMPT_COMMAND=history -a; history -a; printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
env[20]:XDG_RUNTIME_DIR=/run/user/1003
env[21]:HISTTIMEFORMAT=%F %T 
env[22]:OLDPWD=/home/hbr/linux
env[23]:_=./mytest

常用getenv和putenv函数来访问特定的环境变量。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc,char* argv[],char *env[])
{printf("%s\n",getenv("PATH"));return 0;
}
[hbr@VM-16-9-centos environment_variable]$ ./mytest 
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/hbr/.local/bin:/home/hbr/bin

4、环境变量的组织方式

  • 每个程序启动时都会接收一个环境变量表,这个表是通过一个字符指针数组实现的,其中每个指针都指向一个以空字符('\0')结尾的字符串。这些字符串包含了环境变量的信息,是以键值对的形式存在的,每一对都记录着系统或者程序运行时需要的某些特定信息。
  • 环境变量广泛应用于不同的上下文中,它们可以在进程的执行环境中被查询和修改。例如,在Bash这样的命令行环境中,当我们执行一个命令如ls时,Bash会利用PATH这一环境变量来查找并执行相应的ls命令。PATH环境变量包含了一系列目录,系统会在这些目录中搜索可执行文件。
  • 在程序启动时,这些环境变量以字符串数组的形式传递给主函数(main函数),主函数可以通过这个数组来访问和使用环境变量中的信息。这个机制为程序提供了一种灵活的方式来获取运行时的配置信息,使程序能够在不同的环境中更加灵活地运行

5、环境变量具有全局属性

#include <stdio.h>
#include <stdlib.h>int main()
{char * env = getenv("MYENV");if(env){printf("%s\n", env);}return 0;
}
  • 直接查看,发现没有结果,说明该环境变量根本不存在。
设置环境变量 export MYENV="hello world"
再次运行程序,发现结果有了,说明:环境变量是可以被子进程继承下去的。
  • 进程会继承父进程的环境变量,这意味着当创建一个新的子进程时,它会继承父进程的环境变量。这些环境变量包括操作系统的全局环境变量以及在父进程中设置的自定义环境变量。在 Bash 终端中,环境变量的一部分是来自操作系统,另一部分是由用户定义的。
  • 这种继承机制确保了子进程可以在与父进程相同的环境中执行命令,无需重新设置环境变量,从而提供了一种方便的环境共享方式。因此,Bash 的环境变量部分来源于操作系统,同时也包括了用户在 Bash 中自定义的环境变量,这些变量将被子进程继承和使用。

6、命令行参数 

命令行参数是指在程序执行时从命令行中传递给程序的参数。这些参数允许用户在运行程序时向程序传递额外的信息或配置选项。

  • 命令行参数的形式:命令行参数通常以字符串形式传递给程序。它们可以是单词、数字、文件路径等,甚至可以是标志或选项。

  • argc 参数argc 是 main 函数的第一个参数,它表示命令行参数的数量。argc 的值至少为1,因为程序名称本身也算作一个参数。

  • argv 参数argv 是 main 函数的第二个参数,它是一个指针数组,每个指针指向一个以 null 结尾的字符串,代表一个命令行参数。argv[0] 包含程序的名称,而 argv[1]argv[2] 等则包含传递给程序的其他参数。

例如,假设我们有一个名为 example 的程序,并且我们运行以下命令:

./example arg1 arg2 arg3

 在这个例子中,argc 的值为4,argv 数组中包含以下内容:

  • argv[0]:指向字符串 ./example,表示程序的名称。
  • argv[1]:指向字符串 arg1,表示第一个命令行参数。
  • argv[2]:指向字符串 arg2,表示第二个命令行参数。
  • argv[3]:指向字符串 arg3,表示第三个命令行参数。

通过命令行参数,用户可以向程序传递不同的数据或配置信息,使程序更加灵活和通用。

我们来看下面程序 :

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc,char* argv[])
{if(argc!=2){printf("Usage:%s 至少要有一个选项\n",argv[0]);}if(strcmp("-a",argv[1])==0){printf("这是功能一\n");}else if(strcmp("-b",argv[1])==0){printf("这是功能二\n");}return 0;
}

输出结果: 

[hbr@VM-16-9-centos environment_variable]$ ./mytest 
Usage:./mytest 至少要有一个选项
Segmentation fault
[hbr@VM-16-9-centos environment_variable]$ ./mytest -a
这是功能一
[hbr@VM-16-9-centos environment_variable]$ ./mytest -b
这是功能二

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.cpky.cn/p/10462.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

【stm32】hal库学习笔记--定时器输出PWM波

【stm32】hal库学习笔记–定时器输出PWM波 PWM波原理 输出比较 输入捕获 驱动函数 定时器驱动函数 PWM波驱动函数 定时器基本不使用DMA方式 定时器中断处理通用函数 HAL_TIM_IRQHandler实验一:输出固定占空比PWM波 时钟树配置 PF9 改为tim14CH1 tim14配置 开启tim14全局中…

云计算、区块链、大数据之间的关系与特点

云计算、区块链和大数据是当前信息技术领域的热门话题&#xff0c;它们之间有一定的联系和共同点&#xff0c;同时也有不同的特点。 云计算&#xff08;Cloud Computing&#xff09; 是一种基于互联网的计算模式&#xff0c;通过网络提供可按需使用、可扩展和可配置的计算资源…

20240312-2-贪心算法

贪心算法 是每次只考虑当前最优&#xff0c;目标证明每次是考虑当前最优能够达到局部最优&#xff0c;这就是贪心的思想&#xff0c;一般情况下贪心和排序一起出现&#xff0c;都是先根据条件进行排序&#xff0c;之后基于贪心策略得到最优结果。 面试的时候面试官一般不会出贪…

SingleSpa微前端基本使用以及原理

先说说singleSpa的缺点 不够灵活 不能动态加载css文件css不隔离没有js沙箱的机制 ( 没有全局对象 每次切换的应用 都是同一个window ) 但是刚刚接触微前端 可以了解一下微前端的基础使用 qiankun微前端框架已经很成熟 也是基于singleSpa来实现的 点击跳转qiankun的基础使用 大…

MySQL 面试题及答案整理,最新面试题

MySQL中InnoDB和MyISAM存储引擎的区别是什么&#xff1f; InnoDB和MyISAM是MySQL中两种常见的存储引擎&#xff0c;它们的主要区别包括&#xff1a; 1、事务支持&#xff1a; InnoDB支持事务&#xff0c;而MyISAM不支持。 2、行级锁和表级锁&#xff1a; InnoDB提供行级锁&a…

数学建模-模糊性综合评价模型

中医药是中国传统文化的重要组成部分&#xff0c;凝聚了中华民族千百年来智慧的结晶。作为中医的发源地&#xff0c;中国政府一直致力于保护、发展和推广中医药&#xff0c;采取了一系列政策措施[]。目前&#xff0c;中国面临着老龄化日益加剧&#xff0c;老年人群中慢性疾病和…