Linux kill命令原理及源码实现

在 Linux 环境上工作时,你可能会看到应用程序或命令行进程卡住。 那么在这些情况下,终止它是唯一的出路。

Linux 中的 kill 命令(位于 /bin/kill),是一个内置命令,用于手动终止进程。 kill 命令非常易于理解和使用。 kill 命令向终止进程的进程发送信号。 如果用户没有指定要与 kill 命令一起发送的任何信号,则发送默认的 TERM 信号以终止进程。

什么是信号

官方的解释是:

A signal is an asynchronous notification sent to a process or to a
specific thread within the same process in order to notify it of an
event that occurred.

信号是发送到进程或同一进程内的特定线程的异步通知,以通知它发生的事件 。

Unix and Linux like operating systems processes uses SIGNALS in order to communicate each other. For example If we can to kill a process we need to send a signal to process we want to kill. This signal will be SIGTERM and send by kill or similar commands. In this tutorial we will examine the SIGTERM signal and compare with SIGKILL signal.

Unix和Linux之类的操作系统进程使用SIGNALS进行通信。 例如,如果我们可以终止进程,则需要向要终止的进程发送信号。 该信号将是SIGTERM,并通过kill或类似命令发送。

简单理解就是你发个SIGKILL给一个进程,该进程就知道用户要杀死它,然后就会终止进程。

信号的名称和值

可以使用kill –l命令查看当前系统可使用的信号有哪些。

在这里插入图片描述
这些名字都以3个字符SIG开头。不存在编号为0的信号。其中1-31号信号称之为常规信号(也叫普通信号或标准信号),34-64称之为实时信号,驱动编程与硬件相关。名字上区别不大。而前32个名字各不相同。

在 Linux 下,可以查看 signal(7) 手册页来查阅信号名列表、信号值、默认的行为和它们是否可以被捕获。其命令如下所示:

在这里插入图片描述

SIGTERM与SIGKILL

SIGTERM和SIGKILL提供类似的功能。 两者都杀死给定的进程或程序。 但是有一些细微的差别。

1、SIGTERM试图礼貌地杀死对方SIGKILL会严厉地杀死
2、可以处理SIGTERM,但不能处理SIGKILL
3、SIGTERM是杀死进程的第一种方法,但是它不起作用。可以使用SIGKILL。

认识kill命令

kill 命令通常用于杀死进程。 它在内部发送一个信号,根据您想要做什么,您可以使用此工具发送不同的信号。 以下是命令的语法:

kill [options] < pid > […]

如何使用kill命令终止进程?

kill 命令向正在运行的进程发送信号(默认情况下为 SIGTERM 信号)。 此默认操作通常会停止进程。 如果要停止进程,使用 ps 命令来获取应用程序的 pid,然后将其传递给 kill 命令以终止它。

> 这里是引用

如果在普通用户下,我们可能需要将SIGTERM信号发送到root或其他用户进程。 我们可以在其他命令中使用sudo命令获得root特权,这将使我们有能力杀死Linux系统中的所有进程。

在这里插入图片描述

kill命令源码实现


const char *signm[] = { 0,
"HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "EMT", "FPE",	/* 1-8 */
"KILL", "BUS", "SEGV", "SYS", "PIPE", "ALRM", "TERM", 0,	/* 9-16 */
"STOP", "TSTP", "CONT", "CHLD", "TTIN", "TTOU", "TINT", "XCPU",	/* 17-24 */
"XFSZ", 0, 0, 0, 0, 0, 0, 0,					/* 25-31 */
};

static void usage(void)
{

	(void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
		"usage: kill [-s signal_name] pid ...",
		"       kill -l [exit_status]",
		"       kill -signal_name pid ...",
		"       kill -signal_number pid ...");
#ifdef SHELL
	error(NULL);
#else
	exit(2);
#endif

}
static void printsignals(FILE *fp)
{
	int n;

	for (n = 1; n < NSIG; n++) {
		(void)fprintf(fp, "%s", signm[n]);
		if (n == (NSIG / 2) || n == (NSIG - 1))
			(void)fprintf(fp, "\n");
		else
			(void)fprintf(fp, " ");
	}
}

static void nosig(const char *name)
{

	warnx("unknown signal %s; valid signals:", name);
	printsignals(stderr);
#ifdef SHELL
	error(NULL);
#else
	exit(2);
#endif
}

static int signame_to_signum(const char *sig)
{
	int n;

	if (strncasecmp(sig, "SIG", 3) == 0)
		sig += 3;
	for (n = 1; n < NSIG; n++) {
		if (!strcasecmp(signm[n], sig))
			return n;
	}
	return -1;
}


int main(int argc, char *argv[])
{
	long pidl;
	pid_t pid;
	int errors, numsig, ret;
	char *ep;

	if (argc < 2)
		usage();

	numsig = SIGTERM;

	argc--, argv++;
	if (!strcmp(*argv, "-l")) {
		argc--, argv++;
		if (argc > 1)
			usage();
		if (argc == 1) {
			if (!isdigit(**argv))
				usage();
			numsig = strtol(*argv, &ep, 10);
			if (!**argv || *ep)
				errx(2, "illegal signal number: %s", *argv);
			if (numsig >= 128)
				numsig -= 128;
			if (numsig <= 0 || numsig >= NSIG)
				nosig(*argv);
			printf("%s\n", signm[numsig]);
			return (0);
		}
		printsignals(stdout);
		return (0);
	}

	if (!strcmp(*argv, "-s")) {
		argc--, argv++;
		if (argc < 1) {
			warnx("option requires an argument -- s");
			usage();
		}
		if (strcmp(*argv, "0")) {
			if ((numsig = signame_to_signum(*argv)) < 0)
				nosig(*argv);
		} else
			numsig = 0;
		argc--, argv++;
	} else if (**argv == '-' && *(*argv + 1) != '-') {
		++*argv;
		if (isalpha(**argv)) {
			if ((numsig = signame_to_signum(*argv)) < 0)
				nosig(*argv);
		} else if (isdigit(**argv)) {
			numsig = strtol(*argv, &ep, 10);
			if (!**argv || *ep)
				errx(2, "illegal signal number: %s", *argv);
			if (numsig < 0)
				nosig(*argv);
		} else
			nosig(*argv);
		argc--, argv++;
	}

	if (argc > 0 && strncmp(*argv, "--", 2) == 0)
		argc--, argv++;

	if (argc == 0)
		usage();

	for (errors = 0; argc; argc--, argv++) {
#ifdef SHELL
		if (**argv == '%')
			ret = killjob(*argv, numsig);
		else
#endif
		{
			pidl = strtol(*argv, &ep, 10);
			/* 检查pid_t 是否溢出 */
			pid = (pid_t)pidl;
			if (!**argv || *ep || pid != pidl)
				errx(2, "illegal process id: %s", *argv);
			ret = kill(pid, numsig);
		}
		if (ret == -1) {
			warn("%s", *argv);
			errors = 1;
		}
	}

	return errors;
}

编译运行

在这里插入图片描述
kill命令的工作原理是向Linux系统的内核发送一个系统操作信号和某个程序的进程标识号,然后系统内核就可以对进程标识号指定的进程进行操作。

注意:进程号可以通过jps/ps/pidof/pstree/top等工具获取

kill -9 PID

如果SIGTERM无法正常运行,我们可以使用SIGKILL的苛刻方式。 我们可以使用带有-9选项的kill命令发送SIGKILL信号,该命令指定SIGKILL信号。

要停止所有进程并注销自己,请输入以下命令:

kill -9 0

这将向所有进程组 ID 等于发送方进程组 ID 的进程发送信号 9,即 SIGKILL 信号。 由于 shell 无法忽略 SIGKILL 信号,因此此命令还会停止登录 shell 并将您注销

要停止您拥有的所有进程,请输入以下命令:

kill -9 -1

该命令向有效用户拥有的所有进程发送信号 9,即 SIGKILL 信号,甚至是那些在其他工作站启动并属于其他进程组的进程。 如果正在打印您请求的列表,它也会停止。

信号设置为忽略状态

当一个程序执行时,所有信号的状态都是系统默认或忽略。通常所有信号都被设置为它们的默认动作,除非调用exec的进程忽略该信号。

shell如何处理针对后台的处理方式设置为忽略。对于一个非作业控制shell,当在后台执行一个进程时,例如:

./my_kill &

shell自动将后台进程对中断和退出信号的处理方式设置为忽略。我们当按下中断字符时就不会影响到后台进程。

总结

信号用于大多数复杂的应用程序中,理解进行信号处理的原因和方式对于linux编程及其重要。

欢迎关注微信公众号【程序猿编码】,欢迎添加本人微信号(17865354792)交流学习。

参考:UNIX环境高级编程

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux中的kill命令用于终止指定的进程的运行。它通过向进程发送信号来结束相应进程。默认情况下,kill命令发送编号为15的TERM信号,这将终止所有不能捕获该信号的进程。对于那些可以捕获该信号的进程,可以使用编号为9的kill信号,强制终止该进程。\[1\] 在使用kill命令时,需要先获取要终止进程的PID,可以使用ps、pidof、pstree、top等工具来获取。然后使用kill命令加上PID来终止相应的进程。例如,使用kill -9 PID命令可以强制终止指定PID的进程。\[1\] 需要注意的是,有些进程可能具有特殊权限或保护机制,导致无法通过kill命令终止。在这种情况下,可能需要使用sudo命令来提升权限,以便成功终止进程。\[2\] 总结起来,Linux中的kill命令是用于终止指定进程的常用命令。它通过发送信号给进程来结束其运行。默认情况下,使用编号为15的TERM信号,但也可以使用编号为9的kill信号来强制终止进程。\[3\] #### 引用[.reference_title] - *1* [每天一个linux命令(42):kill命令](https://blog.csdn.net/peida/article/details/103397370)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Linuxkill 命令](https://blog.csdn.net/Dancen/article/details/117299111)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Linux 中的 kill 命令](https://blog.csdn.net/Toml_/article/details/130886225)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值