【Linux操作系统】:信号
Linux操作系统下的信号
一、引言
首先我们可以简单理解一下信号的概念,信号,顾名思义,就是我们操作系统发送给进程的消息。举个简单的例子,我们在写C/C++程序的时候,当执行a / 0类似的操作的时候,程序直接就挂了,这是什么原因呢?其实本质就是CPU在计算的时候出现异常,触发硬件中断,然后我们操作系统发送了对应的信号给进程,然后我们进程默认就退出了。这一系列东西,我都将在后续的文章中具体的提到。
二、Linux下信号的形式
管他知不知道了不了解,我们都可以先看看Linux下的信号具体长什么样
这里我简单的介绍几种常见的信号
- SIGINT : 这个信号就是我们常用ctrl + c,他默认的作用就是直接将我们的进程退出。
- SIGSEGV:这个就是段错误的信号,比如我们常见的越界,野指针都是这个错误。
- SIGCHLD:子进程退出的时候,我们父进程可以hang住,也就是阻塞等待,也可以轮询非阻塞等待,或者也可以通过这个信号,所以这个信号就是子进程退出的的时候发送给我们父进程的信号。
- SIGKILL:这个信号可以杀死大部分的进程(D状态进程除外),后续我们也会讲解。
三、信号的产生
- 由内核产生
内核在检测到系统事件或异常时会向进程发送信号,例如:
-
硬件异常:如进程访问非法内存(SIGSEGV)、除零错误(SIGFPE)等。
-
资源限制:进程占用资源超限(如 SIGXCPU 表示CPU时间超限)。
-
子进程状态变化:子进程终止时会向父进程发送 SIGCHLD。
-
终端事件:如终端关闭时发送 SIGHUP,用户按下 Ctrl+C 触发 SIGINT。
- 由其他进程发送
进程可以通过系统调用 kill() 向其他进程发送信号:
复制
#include <signal.h>
int kill(pid_t pid, int sig); // 向指定PID的进程发送信号
// 实例
kill(1234, SIGTERM) // 向PID为1234的进程发送终止信号。
kill(-1, SIGKILL) // 向所有进程发送 SIGKILL(需权限)。
kill(1234, SIGTERM) 向PID为1234的进程发送终止信号。
kill(-1, SIGKILL) 向所有进程发送 SIGKILL(需权限)。
- 由用户或终端触发
键盘快捷键:
-
Ctrl+C → 发送 SIGINT(中断进程)。
-
Ctrl+Z → 发送 SIGTSTP(暂停进程)。
-
Ctrl+\ → 发送 SIGQUIT(终止并生成核心转储)。
-
命令行工具:
kill -9 PID:发送 SIGKILL(强制终止进程)。
pkill -HUP process_name:发送 SIGHUP(重新加载配置)。
- 进程自身触发
进程可以通过 raise() 或 kill() 向自己发送信号:
raise(SIGALRM); // 等同于 kill(getpid(), SIGALRM);
常见用途:
定时器到期(SIGALRM)。
自定义信号处理(如 SIGUSR1/SIGUSR2)。
- 通过条件触发
某些系统调用或条件会隐式产生信号:
alarm():设置定时器,到期后发送 SIGALRM。
sigqueue():发送信号并附加数据(实时信号)。
管道或套接字断开:如写入已关闭的管道会触发 SIGPIPE。
复制
#include <signal.h>
#include <stdio.h>void handler(int sig) {printf("Received SIGINT!\n");
}int main() {signal(SIGINT, handler); // 注册处理函数while(1) {} // 无限循环
}
四、信号的保存(重要)
1. 操作系统如何管理信号
这里我们首先首先要列出内核的信号相关的数据结构
内核中,我们的进程数据结构(struct task_struct)中维护了三张表:
- block : 阻塞表,表示哪些信号是需要阻塞的
- pending: 未决的信号,比如我们一个信号被进程接受到,但是block表中阻塞了他,这个时候,我们的pending表中对应的信号的位置就会置一,表示这个信号处于未决的状态。
- handler表:存储我们对应的函数指针数组,记录没有对应的信号的处理方式,我们的signal函数就是将对应的函数指针填充进入这张表中。
2. 我们如何在用户层修改表结构
这里的各种表结构都是位图(操作系统减少内存的消耗),那么既然使用了位图,操作这些表就会比较困难,所以操作系统为我们提供了相关的接口。
这里的sigset就是我们的位图结构,我们可以通过这些接口,操作一个创建出一个定制化的位图结构。
sigpending就是回去当前(调用这个接口的是偶)的pending表。
sigprocmask可以根据我们的需求定制化设置block表的内容,并且可以取出原来的block表。
3. 当信号来到我们的进程的时候,我们的操作如何对其进行组织和管理
- 当信号来到我们的进程的时候,我们的进程首先进行上下文保护,将我们当前执行的情况保存,然后陷入内核。
- 处理本次信号的问题:但是在处理之前,我们需要检查一下block表,1. 如何什么block表表示我们当前的信号是阻塞的,将pending表中对应的位置置一,表示这个信号处于未决的状态,恢复上下文,回到用户态,继续刚才的代码。 2.如何信号没有阻塞,那么回到用户态,执行我们定制化的handler(也可能是退出)。
- 再次回到内核态(为什么这次还要回到内核态呢? 当然是因为我们还要找到刚才代码执行的位置)。
- 这个时候从内核态找到刚才执行的位置,再次回到用户态继续执行刚才的代码。
细节剖析:
- 细节一: 操作系统规定,每次从内核态到用户态的时候都要检查pending表。
这里可以用以个场景来解释pending表检查:
我们的代码最开始的时候block将SIGINT信号进行的阻塞,表示不处理这个信号
这个时候如果我们接收到了SIGINT信号,这个时候pending表中SIGINT被置一,表示
未决, 后续我们如果通过sigprocmask修改block表,SIGINT不阻塞了,这个操作并不会
触发信号检查(也就是说就算我们这个信号不阻塞了,也不会检查pending表是否有未决的对应信号),也就是说,如果我的后续代码没有任何系统调用,那么即使pending[SIGINT] == 1
仍然不会触发任何检查,只有我们在其他地方触发系统调用(getpid() , 或者类似再次SIGINT),才会调用
也就是说任何的系统调用都会触发pending表检查
- 细节二: 我们总是在内核态转成用户态的时候检查了pending表(是否有未决的信号)
五、信号的处理机制
信号既然能够产生,那么我们肯定可以针对自身的需求,定制对应的回调处理函数,操作系统也为我们提供了对应的函数的接口,这个接口的名字就叫做signal
- signum : 就是表示我们想要针对哪个函数定义对应的回调机制。
- handler: 对应的回调函数,这里的参数是一个函数指针
有了这种机制,我们就可以定制化我们信号处理机制。
我这里提供了一个实例代码,我通过signal函数屏蔽了CTRL + C的默认功能,可以看见,当我进行ctrl + c的时候,程序并没有退出,而是执行我定义的handler函数。
一些注意事项
- 虽然操作系统给我们提供了定制化handler的接口,但是也不能让我们为所欲为,比如前面说的SIGKILL接口就不能重新设置,这保证我们总是可以kill -9杀掉这个进程。
- 默认和忽略
#define SIG_DFL ((__sighandler_t) 0))
#define SIG_IGN ((__sighandler_t) 1))
操作系统给我们定义了一些宏帮助我们进程默认和忽略设置,比如如果我将signal的第二个参数设置成SIG_IGN就表示我忽略这个信号
基于信号再谈谈操作系统
看到了信号,信号是如何触发的,无非就是内核产生(软件中断),硬件中断,也就是说信号是基于中断产生的,一旦有中断就产生对应的信号,那操作系统呢,也是一样的,操作系统就是基于软件中断(系统调用),硬件中断进行执行,我们可以这样理解,操作系统就是一个死循环。
当各种硬件中断来了(按了键盘)就执行对应的硬件中断函数,当触发了软中断(各种系统调用getpid(), open()),就调用软件中断表中的对应函数。
总结:操作系统,就是基于中断的可执行程序。
相关文章:
【Linux操作系统】:信号
Linux操作系统下的信号 一、引言 首先我们可以简单理解一下信号的概念,信号,顾名思义,就是我们操作系统发送给进程的消息。举个简单的例子,我们在写C/C程序的时候,当执行a / 0类似的操作的时候,程序直接就挂…...
skynet.call使用详解
目录 skynet.call 详细解析1. 函数签名与参数2. 内部实现机制3. 会话ID与协程调度4. 超时与错误处理5. 返回值处理6. 协议类型的影响7. skynet.call vs skynet.send8. 示例代码分析9. 最佳实践10. 总结 skynet.call 详细解析 1. 函数签名与参数 函数签名: skynet…...
uniapp 打包 H5 向 打包的APP 使用 @dcloudio/uni-webview-js 传值
1.安装 dcloudio/uni-webview-js npm install dcloudio/uni-webview-js -save 这个模块的 uni. 会与H5的uniapp的 uni. 冲突,所以需要改下名称,一共需要改3处 2.引入并使用 import uniWeb from dcloudio/uni-webview-js;uniWeb.postMessage({data: {action: message,content…...
c语言 文件操作
c语言 文件操作 one 打开/usr/dev.txt文件,在第1行 覆盖写入 "MAC1q23456789" #include <fcntl.h> #include <unistd.h> #include <string.h> int main() { const char *line_1 "MAC1q23456789\n"; // 要写入的内容…...
企业电子招投标采购系统——功能模块功能描述+数字化采购管理 采购招投标
功能描述 1、门户管理:所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含:招标公告、非招标公告、系统通知、政策法规。 2、立项管理:企业用户可对需要采购的项目进行立项申请,并提交审批,查看…...
Python 序列构成的数组(序列的增量赋值)
序列的增量赋值 增量赋值运算符 和 * 的表现取决于它们的第一个操作对象。简单起 见,我们把讨论集中在增量加法()上,但是这些概念对 * 和其他 增量运算符来说都是一样的。 背后的特殊方法是 iadd (用于“就地加法”&…...
力扣hot100【链表】
160.相交链表 题目 我的思路:两个链表一长一短,先把长的提前遍历使两个链表的长度相等,然后同时遍历,如果遍历的节点相等时说明相交,否则不相交。 /*** Definition for singly-linked list.* struct ListNode {* …...
PyTorch 生态迎来新成员:SGLang 高效推理引擎解析
SGLang 现已正式融入 PyTorch 生态系统!此次集成确保了 SGLang 符合 PyTorch 的技术标准与最佳实践,为开发者提供了一个可靠且社区支持的框架,助力大规模语言模型(LLM)实现高效且灵活的推理。 如需深入了解 PyTorch…...
C++ Primer Plus 编程练习题 第六章 分支语句和逻辑运算符
1.大小写转换 使用cctype库里的函数进行大小写转换,但要注意使用toupper或tolower时要进行强制类型转换,否则会输出ASCII值 #include <iostream> #include<cctype> using namespace std;int main() {cout << "请输入字符串(大…...
一文详解OpenGL环境搭建:Windows使用CLion配置OpenGL开发环境
在计算机图形学的广阔领域中,OpenGL作为行业标准的图形库,为开发者提供了强大的工具集来创建从简单的2D图形到复杂的3D世界。然而,对于初学者和经验丰富的开发者而言,选择一个合适的开发环境是迈向成功的第一步。尤其是在Windows平台上,配置一个既支持现代C++编程实践又能…...
一次奇怪的enq: TX - row lock contention锁问题处理
某天上午客户告知数据库库有锁导致数据库卡死,需排查出问题的原因,从根本上解决问题。 按正常步骤,查询V$SESSION中BLOCKING_SESSION列不为空的,发现没有进程互相阻塞的情况;而查询ACTIVE会话,则有大量进程…...
STL常用容器整理
STL常用容器操作整理 STL常用容器操作整理(string/vector/set/map)一、string(字符串)构造函数元素访问修改操作容量操作子串与查找 二、vector(动态数组)构造函数元素访问修改操作容量操作 三、set&#x…...
深入 PostgreSQL 内部:5 个关键阶段拆解查询处理全流程
引言 当您向 PostgreSQL 发送查询时,后端会经历多个处理阶段。每个阶段承担着不同的职责,以确保您能在最短时间内获得准确响应。虽然这些阶段可能庞大而复杂,但理解它们在查询处理中的角色对 PostgreSQL 开发者至关重要。本文将概述每个查询…...
解析 LILIkoi 光纤力传感器:FBG 原理铸就耐高温抗干扰优势
LILIkoi光纤力传感器通过光纤光栅(FBG)技术实现高精度力测量。其核心原理基于光纤内光栅栅距的微小变化,用以感知外界施加的力。该传感器在高温、强辐射等恶劣环境中表现出色,能够有效抵抗电磁干扰和温度漂移。凭借卓越的性能&…...
SU-YOLO:基于脉冲神经网络的高效水下目标检测模型解析
论文地址:https://arxiv.org/pdf/2503.24389 目录 一、论文概述 二、创新点解析 1. 基于脉冲的水下图像去噪(SpikeDenoiser) 原理与结构 2. 分离批归一化(SeBN) 原理与结构 3. 优化的残差块(SU-Block) 原理与结构 三、代码复现指南 环境配置 模型训练 四、…...
有关eeprom以及pwm
a0 a1就是对应的 芯片的 写和读 0写 1读 使用操作 主函数读一次 然后信息里一直写入。 用level设置挡位 如 10个格子 设置2 3 这样占空比就有了...
JMeter教程|0到1学会接口性能压测第14课-JMeter接口性能测试全流程讲解
Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件。相比Loadrunner而言,JMeter小巧轻便且免费,逐渐成为了主流的性能测试工具,是每个测试人员都必须要掌握的工具之一。 本文以百度搜索接口为例,全流程讲解JMeter接口性能测试。从JMeter下载安装到编写一个…...
系统思考:问题诊断
“做事不怕困难,怕的是不明白困难出在哪里。” —— 亨利福特 最近发现,有些领导者或者团队,常常急于给出解决方案,却忽视了最关键的一步——诊断问题的根源。团队甚至在集体心智模式的影响下,连问题本身都搞错了方向…...
有效压缩 Hyper-v linux Centos 的虚拟磁盘 VHDX
参考: http://www.360doc.com/content/22/0505/16/67252277_1029878535.shtml VHDX 有个不好的问题就是,如果在里面存放过文件再删除,那么已经使用过的空间不会压缩,导致空间一直被占用。那么就需要想办法压缩空间。 还有一点&a…...
使用 redis 实现消息队列
方案1: 使用list做消息队列问题1: 如何保证消息不丢失问题 2: 重复消费/幂等 方案 2: zset实现消息队列方案 3: 发布/订阅(pub/sub)问题1: 如何保证消息不丢失问题 2: 重复消费/幂等 方案 4: Stream 实现消息队列问题1: 如何保证消息不丢失问题 2: 重复消费/幂等 方案1: 使用li…...
2025 XYCTF Pwn-wp(含附件)
前言 总体来说Pwn方向题目难度属于中等,属于那种一眼看不出要咋做,但多试试又能做出来的那种,比赛的时候甚至有几只队伍AK了Pwn方向。感觉题目还是很不错的尽管比赛中有一些小意外像是有些题目附件给错了,但是XYCTF的师傅们都是无偿出题纯热爱向大伙分享自己的题目…...
verilog有符号数的乘法
1、单周期乘法器 对于低速要求的乘法器,可以简单的使用 * 实现。 module Mult(input wire [7:0] multiplicand ,input wire [7:0] multipliter ,output wire [7:0] product);assign product multiplicand * multipliter …...
【python3】关于等额本金和等额本息计算
【python3】关于等额本金和等额本息计算 1.背景2.计算3.总结4.推导 1.背景 在贷款买房的宝子们一定有了解等额本金和等额本息,年轻的时候只听销售在那里计算, 您可能听得云里雾里。 等额本金:每个月还的本金固定,利息逐渐减少。…...
git怎么删除远程分支
删除远程分支 引言删除远程分支查看远程分支查看远程分支详情删除远程分支 引言 本文旨在记录一下,git如何通过命令行删除远程分支。 删除远程分支 查看远程分支 使用指令: git branch -r查看远程分支详情 使用指令: git remote show …...
【C++】函数直接返回bool值和返回bool变量差异
函数直接返回bool值和返回bool变量差异 背景 在工作中遇到一个比较诡异的问题,场景是给业务方提供的SDK有一个获取状态的函数GetStatus,函数的返回值类型是bool,在测试过程中发现,SDK返回的是false,但是业务方拿到的…...
蓝桥杯-蓝桥幼儿园(并查集)
并查集的核心思想 并查集主要由两个操作构成: Find:查找某个元素所在集合的根节点。并查集的特点是,每个元素都指向它自己的父节点,根节点的父节点指向它自己。查找过程中可以通过路径压缩来加速后续的查找操作,即将路…...
Ensemble of differential evolution variants(EDEV)
差分进化变体的集成1 在这项研究中,一个基于多种群的框架(MPF)被提议用于多个差分进化变体的集合。与PAP2不同,PAP通过时间预算分配策略和个体移民算子实现算法组合,MPF将整个种群划分为子种群,包括几个指…...
《AI开发工具和技能实战》第1集 Windows CMD 命令行操作指南:从基础到进阶
第1集 Windows CMD 命令行操作指南:从基础到进阶 在日常使用 Windows 系统时,命令提示符(Command Prompt,简称 CMD)是一个强大且灵活的工具。无论是文件管理、系统配置,还是网络诊断,CMD 都能提…...
实现一个拖拽排序组件:Vue 3 + TypeScript + Tailwind CSS
文章目录 一、项目背景与需求分析需求: 二、搭建基础项目1. 初始化 Vue 3 项目2. 安装 Tailwind CSS 三、设计拖拽排序组件1. 创建拖拽排序组件2. 说明: 四、完善样式与功能1. 样式调整2. 拖拽顺序更新 五、进一步优化与拓展1. 添加排序指示器2. 支持动态…...
哈希表(开散列)的实现
目录 引入 开散列的底层实现 哈希表的定义 哈希表的扩容 哈希表的插入 哈希表查找 哈希表的删除 引入 接上一篇,我们使用了闭散列的方法解决了哈希冲突,此篇文章将会使用开散列的方式解决哈希冲突,后面对unordered_set和unordered_map的…...
解决 Jetpack Compose 中 State 委托报错:“no method getValue“ 的终极指南
1. 必须的导入 ✅ import androidx.compose.runtime.getValue // 核心关键!作用:为 State 类型添加 getValue() 操作符,使其支持 by 委托语法。为什么需要:Kotlin 的委托属性需要对象实现 getValue() 方法,Compose 通…...
我们如何思考AI创业投资
🎬 Verdure陌矣:个人主页 🎉 个人专栏: 《C/C》 | 《转载or娱乐》 🌾 种完麦子往南走, 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️ 声明:本文作者转载,原文出自…...
1.ElasticSearch-入门基础操作
一、介绍 The Elastic Stack 包含ElasticSearch、Kibana、Beats、LogStash 这就是所说的ELK 能够安全可靠地获取任何来源、任何格式的数据,然后实时地对数据进行搜索、分析和可视化。Elaticsearch,简称为ES,ES是一个开源的高扩展的分布式全文搜索引擎,是…...
2.ElasticSearch-Java API
一、基础使用 1.1 Maven 坐标 <dependencies><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.8.0</version></dependency><!--es的客户端--><dependenc…...
蓝桥杯-小明的彩灯(差分)
问题描述: 差分数组 1. 什么是差分数组? 差分数组 c 是原数组 a 的“差值表示”,其定义如下: c[0] a[0]c[i] a[i] - a[i-1] (i ≥ 1) 差分数组记录了相邻元素的差值。例如,原数组 a [1, …...
vim定位有问题的脚本/插件的一般方法
在使用vim的过程中可能会遇到一些报错或其他不符合预期的情况,本文介绍一些我自己常用的定位有问题脚本/插件的方法(以下方法同样适用于neovim) 执行了某些命令的情况 这种情况最简单,使用:h 命令,如果插件有文档的话…...
EasyExcel实现图片导出功能(记录)
背景:在旧系统的基础上,导出一些工单信息时,现需要新添加处理人的签名或者签章,这就涉及图片的上传、下载、写入等几个操作。 1、EasyExcel工具类 (1)支持下拉框的导出。 import com.alibaba.excel.Easy…...
PCL拟合空间3D圆周 fit3DCircle
PCL版本 1.15.0 main.cpp #include<vector> #include<iostream> #include <array> #include <string> #include <windows.h> #include <omp.h> #include <charconv> // C17 #include <cstdlib> #include<chrono> #in…...
ansible 实现达梦7数据库初始化数据脚本写入
关于使用ansible 对ARM版达梦7的k8s自动化部署参考我的这篇操作 ansible-playbook 写arm版达梦7数据库的一键安装脚本-CSDN博客文章浏览阅读303次,点赞5次,收藏3次。达梦官方提供镜像目前是dm8_x86 版本,因为众所周知的国产化方面的需求&…...
leetcode每日刷题
Day18 Title45.jump(跳跃游戏 II) 解法一:动态规划 依然分三步走: 1.状态方程 2.dp[i]的意义 3.边界条件及初始值 优先思考第二个问题: dp[i]表示到达i时需要的最少跳数 第一个问题: dp[ij]min(dp[i]1,dp[ij]) 为什么&am…...
Ubuntu安装Nginx
Ubuntu安装Nginx 由于 Ubuntu 的 apt 命令内置了 nginx 源,因此不用配置 apt 就可以直接下载安装: apt install nginx -y查看 nginx 是否启动: ps -ef |grep nginx如果没有启动则需要手动启动: nginx1. 配置Nginx 使用浏览器…...
Hadoop的序列化
(一)什么是序列化与反序列化 序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储到磁盘(持久化)和网络传输。 反序列化就是将收到字节序列(或其他数据传输协议…...
拼多多商品详情接口爬虫实战指南
一、引言 在电商运营和数据分析中,获取商品详情数据是至关重要的一步。拼多多作为国内知名的社交电商平台,提供了丰富的商品详情接口,允许开发者通过API获取商品的详细信息。本文将详细介绍如何通过爬虫技术结合拼多多商品详情接口ÿ…...
python网络爬虫
一、Python爬虫核心库 HTTP请求库 requests:简单易用的HTTP请求库,处理GET/POST请求。aiohttp:异步HTTP客户端,适合高并发场景。 HTML/XML解析库 BeautifulSoup:基于DOM树的解析库,支持多种解析器…...
java线程安全-单例模式-线程通信
首先看看单例模式的写法 首先我们先来回顾一下饿汉式单例模式: class Singleton{private static Singleton singletonnew Singleton();private Singleton(){}public static Singleton getInstrance(){return singleton;} } public class Test{public static void …...
ASP.NET中将 PasswordHasher 使用的 PBKDF2 算法替换为更现代的 Scrypt 或 Argon2 算法
相关博文: .Net实现SCrypt Hash加密_scrypt加密-CSDN博客 密钥派生算法介绍 及 PBKDF2(过时)<Bcrypt(开始淘汰)<Scrypt< Argon2(含Argon2d、Argon2i、Argon2id)简介-CSDN博客 浅述.Net中的Hash算法(顺带对称、非对称…...
力扣刷题-热题100题-第34题(c++、python)
23. 合并 K 个升序链表 - 力扣(LeetCode)https://leetcode.cn/problems/merge-k-sorted-lists/?envTypestudy-plan-v2&envIdtop-100-liked 顺序合并 合并两个有序链表作为子函数,创建一个空链表,然后对含有多个链表的数组进…...
【SpringCloud】从入门到精通【上】
今天主播我把黑马新版微服务课程MQ高级之前的内容都看完了,虽然在看视频的时候也记了笔记,但是看完之后还是忘得差不多了,所以打算写一篇博客再温习一下内容。 课程坐标:黑马程序员SpringCloud微服务开发与实战 微服务 认识单体架构 单体架…...
如何给路由器配置代理IP?更改网络ip地址时出现错误怎么解决?
在现代网络环境中,无论是家庭用户还是企业用户,经常需要配置路由器以实现网络访问的灵活性和匿名性。其中,给路由器配置代理IP是一个常见的需求,尤其是在需要绕过地域限制、增强网络安全或进行匿名浏览时。然而,配置过…...
程序化广告行业(70/89):ABTester系统助力落地页优化实践
程序化广告行业(70/89):ABTester系统助力落地页优化实践 在程序化广告领域摸爬滚打多年,深知持续学习和知识共享的重要性。写这篇博客,就是希望能和大家一起深入探索程序化广告行业,共同学习、共同进步。今…...