前言

接上一篇文章, node 程序后台执行加上 tail 命令, 中断 tail 命令, 同时也中断了 node 程序

我们来详细 参照对比一下 这个问题的各种情况

主要的脚本如下类似, 第一条命令 后台启动 程序1, 然后 第二条命令 tail -f 查看日志

然后 ctrl+c 中断 "tail -f" 第一条命令的进程 也收到了 SIGINT 的信号

nohup node nodeProcess.js > ./logs/nodeNohup.log 2>&1 &
tail -f ./logs/nodeNohup.log

c/node/java 程序的 前台/后台 执行的对比

1. c 程序, 测试程序如下

#include <signal.h>
#include <unistd.h>
#include <stdio.h>/*** sign handler* @param dunno*/
void sigHandler(int dunno) {switch (dunno) {case 1:printf("Get a signal-SIGHUP \n");break;case 2:printf("Get a signal - SIGINT \n");break;case 3:printf("Get a signal - SIGQUIT \n");break;}fflush(stdout);
}int main() {printf("press id is %d \n", getpid());fflush(stdout);signal(SIGHUP, sigHandler);signal(SIGINT, sigHandler);signal(SIGQUIT, sigHandler);struct sigaction sigAction;sigAction.sa_sigaction = sigHandler;sigAction.sa_flags = SA_SIGINFO;struct sigaction existsSigHandler;sigaction(SIGINT, &sigAction, &existsSigHandler);int counter = 0;while (1) {counter ++;}}

新建 cStartUp.sh 脚本如下

master:11_singal2Parent jerry$ cat cStartUp.sh /Users/jerry/ClionProjects/HelloWorld/cmake-build-debug/HelloWorld > ./logs/cNohup.log 2>&1
# /Users/jerry/ClionProjects/HelloWorld/cmake-build-debug/HelloWorld > ./logs/cNohup.log 2>&1 &tail -f ./logs/cNohup.log

在 Clion 中直接 运行/调试

// 调试启动, 分别发送 SIGHUP, SIGINT 到进程, 发现 SIGINT 的 handler 没有生效
press id is 11024
Signal: SIGHUP (signal SIGHUP)
Get a signal-SIGHUP
Signal: SIGINT (signal SIGINT)// 正常启动, 分别发送 SIGHUP, SIGINT 到进程, 两个 handler 都生效
press id is 11047
Get a signal-SIGHUP
Get a signal - SIGINT

分别切换 cStartUp.sh 的前台启动 和 后台启动, 查看现象

# 前台启动时, 分别发送 SIGHUP, SIGINT 到进程, 两个 handler 都生效
master:11_singal2Parent jerry$ tail -f logs/cNohup.log
press id is 11137
Get a signal-SIGHUP
Get a signal - SIGINT # 后台启动时, 分别发送 SIGHUP, SIGINT 到进程, 两个 handler 都生效
press id is 11166
Get a signal-SIGHUP
Get a signal - SIGINT 

cStartUp.sh 的前台启动 和 后台启动时, 中断 "tail -f" 是否向 c程序 发送 SIGINT

# 前台启动时 cStartUp.sh 的日志信息, "^C" 为 ctrl + c 的操作
master:11_singal2Parent jerry$ ./cStartUp.sh
^C# 读取日志文件, 发现 c程序 收到了 SIGINT
master:11_singal2Parent jerry$ tail -f logs/cNohup.log
press id is 11581
Get a signal-SIGHUP
Get a signal - SIGINT
Get a signal - SIGINT # 后台启动时 cStartUp.sh 的日志信息, 下面为 tail -f 的输出, "^C" 为 ctrl + c 的操作
master:11_singal2Parent jerry$ ./cStartUp.sh
press id is 11166
Get a signal-SIGHUP
Get a signal - SIGINT
^Cmaster:11_singal2Parent jerry$ # 读取日志文件, 发现 c程序 收到了 SIGINT
press id is 11166
Get a signal-SIGHUP
Get a signal - SIGINT
Get a signal - SIGINT

2. node 程序, 测试程序如下

process.on('SIGHUP', function() {console.log('SIGHUP');
});process.on('SIGINT', function() {console.log('SIGINT');
});console.log('PID: ', process.pid);var http = require('http'); // HTTP server to keep the script up long enough
http.createServer(function (req, res) {res.writeHead(200, {'Content-Type': 'text/plain'});res.end('Hello World\
');
}).listen(1337, '127.0.0.1');console.log('Server running at http://127.0.0.1:1337/');

nodeStartUp.sh 脚本如下

master:11_singal2Parent jerry$ cat nodeStartUp.sh
nohup node nodeProcess.js > ./logs/nodeNohup.log 2>&1
# nohup node nodeProcess.js > ./logs/nodeNohup.log 2>&1 &tail -f ./logs/nodeNohup.log

在 Webstorm 中直接 运行/调试

// 调试启动, 分别发送 SIGHUP, SIGINT 到进程, 发现 SIGINT 的 handler 没有生效
press id is 11024
Signal: SIGHUP (signal SIGHUP)
Get a signal-SIGHUP
Signal: SIGINT (signal SIGINT)// 正常启动, 分别发送 SIGHUP, SIGINT 到进程, 两个 handler 都生效
press id is 11047
Get a signal-SIGHUP
Get a signal - SIGINT

分别切换 nodeStartUp.sh 的前台启动 和 后台启动, 查看现象

# 前台启动时, 分别发送 SIGHUP, SIGINT 到进程, 两个 handler 都生效
PID:  11461
Server running at http://127.0.0.1:1337/
SIGHUP
SIGINT# 后台启动时, 分别发送 SIGHUP, SIGINT 到进程, 两个 handler 都生效
PID:  11538
Server running at http://127.0.0.1:1337/
SIGHUP
SIGINT

nodeStartUp.sh 的前台启动 和 后台启动时, 中断 "tail -f" 是否向 node程序 发送 SIGINT

# 前台启动时 nodeStartUp.sh 的日志信息, "^C" 为 ctrl + c 的操作
master:11_singal2Parent jerry$ ./nodeStartUp.sh
^C# 读取日志文件, 发现 node程序 收到了 SIGINT
master:11_singal2Parent jerry$ tail -f logs/nodeNohup.log
PID:  11606
Server running at http://127.0.0.1:1337/
SIGHUP
SIGINT
SIGINT# 后台启动时 nodeStartUp.sh 的日志信息, "^C" 为 ctrl + c 的操作
master:11_singal2Parent jerry$ ./nodeStartUp.sh
PID:  11617
Server running at http://127.0.0.1:1337/
SIGHUP
SIGINT
^Cmaster:11_singal2Parent jerry$ # 读取日志文件, 发现 node程序 收到了 SIGINT
PID:  11617
Server running at http://127.0.0.1:1337/
SIGHUP
SIGINT
SIGINT

3. java 程序, 测试程序如下

/*** Test07Signal2ParentProcess** @author Jerry.X.He <970655147@qq.com>* @version 1.0* @date 2022-09-10 19:18*/
public class Test07Signal2ParentProcess {// Test07Signal2ParentProcesspublic static void main(String[] args) throws Exception {String lines = "HUP\n" +"INT\n" +
//                "QUIT\n" +
//                "ILL\n" +"TRAP\n" +"ABRT\n" +"EMT\n" +
//                "FPE\n" +
//                "KILL\n" +"BUS\n" +
//                "SEGV\n" +"SYS\n" +"PIPE\n" +"ALRM\n" +"TERM\n" +"URG\n" +
//                "STOP\n" +"TSTP\n" +"CONT\n" +"CHLD\n" +"TTIN\n" +"TTOU\n" +"IO\n" +"XCPU\n" +"XFSZ\n" +"VTALRM\n" +"PROF\n" +"WINCH\n" +// todo, not work in hostpostVM9
//                "INFO\n" +
//                "USR1\n" +"USR2";for (String sigNo : lines.split("\n")) {Signal.handle(new Signal(sigNo), new SignalHandler() {@Overridepublic void handle(Signal signal) {System.out.println(sigNo);}});}Signal.raise(new Signal("ALRM"));Signal.raise(new Signal("INT"));Thread.sleep(300 * 1000);}}

startUp.sh 脚本如下

master:11_singal2Parent jerry$ cat startUp.sh # java -classpath /Users/jerry/IdeaProjects/HelloWorld/target/classes com.hx.test13.Test07Signal2ParentProcess > ./logs/nohup.log 2>&1 &# java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -classpath /Users/jerry/IdeaProjects/HelloWorld/target/classes com.hx.test13.Test07Signal2ParentProcessjava -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -classpath /Users/jerry/IdeaProjects/HelloWorld/target/classes com.hx.test13.Test07Signal2ParentProcess > ./logs/nohup.log 2>&1 &tail -f ./logs/nohup.log

在 Idea 中直接 运行/调试

// 调试启动, 分别发送 SIGHUP, SIGINT 到进程, 发现 SIGINT 的 handler 没有生效
INT
ALRM// 正常启动, 分别发送 SIGHUP, SIGINT 到进程, 两个 handler 都生效
INT
ALRM

分别切换 startUp.sh 的前台启动 和 后台启动, 查看现象

# 前台启动时, 分别发送 SIGHUP, SIGINT 到进程, 两个 handler 都生效
master:11_singal2Parent jerry$ ./startUp.sh
Listening for transport dt_socket at address: 5005
INT
ALRM
^CINT# 后台启动时, 分别发送 SIGHUP, SIGINT 到进程, SIGINT 的 handler 不生效
# 使用 kill -2 $pid 同样不生效
master:11_singal2Parent jerry$ ./startUp.sh
Listening for transport dt_socket at address: 5005
ALRM

startUp.sh 的前台启动 和 后台启动时, 中断 "tail -f" 是否向 java程序 发送 SIGINT

没有 SIGINT 的日志输出 就表示该 进程没有收到 SIGINT 的信号吗? 不一定

# 前台启动时 startUp.sh 的日志信息, "^C" 为 ctrl + c 的操作
master:11_singal2Parent jerry$ ./startUp.sh
Listening for transport dt_socket at address: 5005
INT
ALRM
^CINT# 后台启动时 startUp.sh 的日志信息, "^C" 为 ctrl + c 的操作
master:11_singal2Parent jerry$ ./startUp.sh
Listening for transport dt_socket at address: 5005
ALRM
^Cmaster:11_singal2Parent jerry$ # 读取日志文件, 没有 SIGINT 的日志输出
Listening for transport dt_socket at address: 5005
ALRM

后台启动时, 使用 gdb 连接后台进程, ctrl + c 的时候, 能够接收到 SIGINT 的信号

Thread 1 "java" received signal SIGINT, Interrupt.
0x00007fb7f452098d in pthread_join (threadid=140428059076352, thread_return=0x7fffb6cb9e08) at pthread_join.c:90
90  in pthread_join.c

ubuntu 中基于 openJdk 调试 Test07Signal2ParentProcess

这里是基于 jvm, linux 的一些调试, 因此 我们期望看到更细节的东西

这里 hotspotVM 基于 openjdk8

比如 注册 SignalHandler 的时候, 是否会有一些不同的处理, 是否注册上

另外就是 发送了 SIGINT 之后的处理?

startUp.sh 的前台启动 和 后台启动时, 中断 "tail -f" 是否向 java程序 发送 SIGINT

在 Clion 中直接 运行/调试

这里的现象和 上面 Clion 调试 HelloWord 的现象一致, 应该是 Clion 的相关代理处理, 导致的问题

// 调试启动, 分别发送 SIGHUP, SIGINT 到进程, 发现 SIGINT 的 handler 没有生效
ALRM// 正常启动, 分别发送 SIGHUP, SIGINT 到进程, 两个 handler 都生效
INT
ALRM

Clion 中调试看一下 注册 SignalHandler, 以及 接收到 SIGINT 之后的处理

SIGHUP 注册了 UserHandler 作为 handler

SIGINT 注册了 UserHandler 作为 handler

通过 raise 准备发送 SIGHUP 的信号

这里往 将 0xea 赋值到 eax, 然后执行 syscall, 0xea 对应的系统调用为 tgkill, 类似于 kill 命令

向给定的 进程发送了 SIGHUP 的信号

resultvar 对应于 eax, 值为 0, 表示 tgkill 的系统调用调用成功

如下是收到了 SIGHUP 的信号之后, 当前进程的处理, 注册的函数是 UserHandler

通过 raise 准备发送 SIGINT 的信号

这里往 将 0xea 赋值到 eax, 然后执行 syscall, 0xea 对应的系统调用为 tgkill, 类似于 kill 命令

向给定的 进程发送了 SIGINT 的信号

resultvar 对应于 eax, 值为 0, 表示 tgkill 的系统调用调用成功

但是后面没有 收到 SIGINT 之后的回调处理, 这个就很奇怪?

这也是我没有搞明白的地方

我们再确认一下 raise 的时候, SIGINT 对应的 handler, 执行 "print os::signal(2, os::user_handler())", sigAct 为新的 handler, oldSigAct 为已有的 handler, 可以发现都是 UserHandler

那就说明我们这里的情况是 tgkill 发送了 SIGINT 成功, 但是 后面操作系统有什么其他的处理?

Clion 远程调试 gdbServer 前台启动的服务, startGdbServer.sh 如下

root@ubuntu:~/Desktop/openJdk/HelloWorld# cat startGdbServer.sh mainClazz=Test07Signal2ParentProcess
classpath=.:./lib/jol-core-0.8.jar:EXISTS_PID=`jps -lvm | grep $mainClazz | grep -v grep | awk '{print $1}'`
if [ "$EXISTS_PID" = "" ]; thenecho " the main class $mainClazz does not startup "
elsekill -9 $EXISTS_PIDecho " the main class $mainClazz shutdown succeed, kill -9 $EXISTS_PID "
figdbserver localhost:1234 /root/Desktop/openJdk/openjdk/build/linux-x86_64-normal-server-slowdebug/jdk/bin/java -XX:+AllowUserSignalHandlers -cp $classpath $mainClazz > ./logs/nohup.log 2>&1
# gdbserver localhost:1234 /root/Desktop/openJdk/openjdk/build/linux-x86_64-normal-server-slowdebug/jdk/bin/java -XX:+AllowUserSignalHandlers -cp $classpath $mainClazz > ./logs/nohup.log 2>&1 & tail -f ./logs/nohup.log

注册 SIGHUP, SIGINT 的 handler, 均为 UserHandler

raise 发送信号之后, 和上面一样 SIGHUP 进入了 UserHandler 的处理, SIGINT 没有进入 UserHandler 的处理

Clion 远程调试 gdbServer 后台启动的服务, startGdbServer.sh 如下

注册 SIGHUP 的 handler, 为 UserHandler, 但是 SIGHUP 的 handler 的注册, 我们发现 居然没有了?

另外就是 raise 发送信号的处理, 也是一样, SIGHUP 的正常发送, 然后 SIGINT 的没有了?

呵呵 这是本文的另外的一个 细节的地方了, 如果 没有调试, 这种现场 估计你想都想不到

看第一个 RegisterSignal, 可以看到 SIGINT 的 handler 为 SIG_IGN

这里对于 SIGHUP, SIGINT, SIGTERM 如果 已有的 handler 是 SIG_IGN 的话, 会直接返回, 返回 1, 表示 handler 为 SIG_IGN

raise 的时候处理如下, SIGINT 的 handler 为 SIG_IGN, 因此 直接 返回了

Clion 远程调试 gdbServer 后台启动的服务, 中断 "tail -f" 是否向 java程序 发送 SIGINT

手动执行 "kill -2 $pid" 是可以看到一个 SIGINT 触发了断点中断

但是当我 ctrl + c 中断 "tail -f " 的时候

在 gdb server 上面接收到了这个 SIGINT 的中断

mac 中基于 openJdk 调试 Test07Signal2ParentProcess

和上述 ubuntu 的相关结论基本一致

是那个进程发送的 SIG_INT?

基于 siginfo_t.si_pid 来获取发送信号的进程的信息


#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "signal.h"void signalHandler(int sigNumber, siginfo_t *info, void *context) {int senderPid = info->si_pid;printf(" process %d, sender process pid %d, got signal %d \r\n", getpid(), senderPid, sigNumber);fflush(stdout);
}void processHandler(int pid, char *processName) {while(1) {printf(" I'm %s, and pid is %d \r\n", processName, pid);fflush(stdout);sleep(2);}
}int main(int argc, char** argv) {// echo -e "nohup /Users/jerry/ClionProjects/HelloWorld/cmake-build-debug/HelloWorld >> logs/nohup.log 2>&1 &\n tail -f logs/nohup.log" >> start.sh// chmod +x start.shstruct sigaction sa;sa.sa_flags = SA_SIGINFO;sa.sa_sigaction = signalHandler;sigaction(2, &sa, NULL);sigaction(3, &sa, NULL);sigaction(4, &sa, NULL);int childPid = fork();if(childPid == 0) {processHandler(getpid(), "child1");} else {int child2Pid = fork();if(child2Pid == 0) {processHandler(getpid(), "child2");} else {processHandler(getpid(), "parent");}}}

再 mac 上面, 无论是 前台启动进程, 还是 后台启动进程 + "tail -f logs/nohup.log", 得到的日志 均是类似于如下

I'm child2, and pid is 2246
I'm child1, and pid is 2245
I'm parent, and pid is 2243
process 2243, sender process pid 488, got signal 2
process 2246, sender process pid 488, got signal 2
process 2245, sender process pid 488, got signal 2
I'm child2, and pid is 2246
I'm child1, and pid is 2245
I'm parent, and pid is 2243

进程树 大致如下 , 可以看到的是 signal 是由 Terminal 这个进程发出的

488      1   0  10:37AM ??         0:27.76 /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal489    488   0  10:37AM ttys000    0:00.02 login -pf jerry// bash 490    489   0  10:37AM ttys000    0:00.19 -bash// start.sh2242   490   0  3:51PM ttys000    0:00.00 -bash2243  2242   0  3:51PM ttys000    0:00.01 /Users/jerry/ClionProjects/HelloWorld/cmake-build-debug/HelloWorld2245  2243   0  3:51PM ttys000    0:00.00 /Users/jerry/ClionProjects/HelloWorld/cmake-build-debug/HelloWorld2246  2243   0  3:51PM ttys000    0:00.00 /Users/jerry/ClionProjects/HelloWorld/cmake-build-debug/HelloWorld2244  2242   0  3:51PM ttys000    0:00.00 tail -f logs/nohup.log

再 linux 上面, 若果是直接 中断 "tail -f", 似乎是拿不到的发送 SIGINT 的进程的进程号的

 I'm child1, and pid is 7521I'm parent, and pid is 7519I'm child2, and pid is 7522process 7522, sender process pid 0, got signal 2I'm child2, and pid is 7522process 7519, sender process pid 0, got signal 2I'm parent, and pid is 7519process 7521, sender process pid 0, got signal 2I'm child1, and pid is 7521I'm child2, and pid is 7522

但是手动 kill 发送信号, 是可以拿到 发送 SIGINT 的进程的进程号的

 I'm child2, and pid is 7522I'm child1, and pid is 7521I'm parent, and pid is 7519process 7521, sender process pid 7336, got signal 2I'm child1, and pid is 7521I'm child2, and pid is 7522I'm parent, and pid is 7519I'm child1, and pid is 7521process 7519, sender process pid 7336, got signal 2I'm parent, and pid is 7519I'm child2, and pid is 7522I'm child1, and pid is 7521process 7522, sender process pid 7336, got signal 2I'm child2, and pid is 7522I'm parent, and pid is 7519I'm child1, and pid is 7521

结论

1. 在后台启动了 c/node/java 程序之后, 添加了一个 "tail -f", 当 ctrl + c 中断 "tail -f" 的时候, 会发送 SIGINT 到对应的 c/node/java 进程

2. 在后台启动 java 进程的场景中, 注册 SIGINT 实际上最终是没有注册成功, 会直接被忽略掉, 发送 SIGINT 信号到给定的进程, 也会被 忽略掉

3. 在后台启动 java 进程的场景中, SIGINT 的 handler 在 java 层面 和 jvm 层面存放的逻辑 handler 不匹配, java 层面拿到的是注册的自定义的 handler, jvm 拿到的的是 SIG_IGN

4. Clion 调试启动程序时候, 对于 SIGINT 信号的支持存在问题 ?

这里大概可以解释 node 程序后台执行加上 tail 命令, 中断 tail 命令, 同时也中断了 node 程序 中的第三个, 第四个问题

3. java 程序这边通过 "startUp.sh" 启动, 进程到底收到 SIGINT 没有?

4. java 程序这边程序中注册的 SIGINT 的 handler 为什么没有生效?, 替换成了什么?

java 程序这边通过 "startUp.sh" 启动, 然后 ctrl + c 中断了 "tail -f" 是收到了 SIGINT 的信号了的

java 程序这边程序中注册的 SIGINT 的 handler

如果是前台启动, 则会为 SIGINT 注册正确的 UserHandler/Test07Signal2ParentProcess$1, raise, kill 也能正确的发送信号, 但是因为神秘的原因, 没有处理这个信号

如果是后台启动, 则 SIGINT 默认注册的 handler 是 SIG_IGN, 因此后面用户手动注册的 handler 是没有注册上的, 然后 raise 的时候, 直接忽略了这个信号请求, 甚至还没有发送信号

这里大概可以解释 node 程序后台执行加上 tail 命令, 中断 tail 命令, 同时也中断了 node 程序 中的第一个问题

1. 但是是 哪一个进程呢 向 node进程 发送的 SIGINT ?

2. 这个进程 为什么要发送 SIGINT 到 node 进程呢 ?

在 mac 中就是 bash 对应的 父进程 发送的 SIGINT 信号

在 linux 中不确定

56/14 shell脚本 后台启动 程序1 + “tail -f log“, ctrl +c 导致程序1中断相关推荐

  1. java源码如何启动脚本_使用Shell脚本如何启动/停止Java的jar程序

    本文介绍如何使用Shell脚本来开启和停止jar程序的后台运行,以及如何实现out大文件的切分.另外,补充一些后台运行的小知识. 启动脚本:start_upload.sh #!/bin/sh nohu ...

  2. nohup执行的jar 怎么kill_使用Shell脚本如何启动/停止Java的jar程序

    本文介绍如何使用Shell脚本来开启和停止jar程序的后台运行,以及如何实现out大文件的切分.另外,补充一些后台运行的小知识. 启动脚本:start_upload.sh #!/bin/sh nohu ...

  3. linux打开pythonshall,linux系统shell脚本后台运行python程序

    python开发的同学们应该都知道怎么样去启动一个python应用,但是一旦我们把python应用部署到linux服务器上该如何启动呢? 方式①:就是使用进程管理工具,比如supervisor.想了解 ...

  4. GDB怎么调试使用.sh(shell脚本)启动的程序?(未完成,待测试)

    1 )直接在shell脚本中调用GDB.这意味着你没有标准的和标准的重定向.(不知道怎么操作..反正没成功) 2)运行shell脚本,然后将调试器附加到已经运行的c ++进程,像这样:gdb prog ...

  5. Jenkins执行shell脚本无法启动子进程解决

    例子:shell脚本 cd /home #test.jar目录 nohup java -jar test.jar --server.port=8081 >test.log 2>&1 ...

  6. Win7运行程序总提示出现一个问题,导致程序停止正常工作。请关闭该程序?原来GreenBrowser下载有问题……

    前段时间借了一位朋友的电脑来用.那台电脑里原有的浏览器不顺手,就先下载安装GreenBrowser,再运行GreenBrowser下载其它的应用程序. 首先下载EditPlus,结果运行时提示: 出现 ...

  7. Win7运行程序总提示出现一个问题,导致程序停止正常工作 请关闭该程序 原来GreenBrowser下载有问题

    前段时间借了一位朋友的电脑来用.那台电脑里原有的浏览器不顺手,就先下载安装GreenBrowser,再运行GreenBrowser下载其它的应用程序. 首先下载EditPlus,结果运行时提示: 出现 ...

  8. php fastcgi进程启动,Shell脚本实现启动PHP内置FastCGI Server

    前几天把工作平台从 Ubuntu 9.10 Karmic 更新到了 10.04 Lucid,由于 Lucid 官方源自带了 PHP5.3.2,以前使用的 dotdeb的源就没法用了,一直很喜欢这个源的 ...

  9. linux 关闭java进程后重启有用吗_linux启动java进程的shell脚本(包括启动,停止,重启)...

    近来使用spring boot写了一个短信服务组件,并配上此段脚本,实现对服务进程的管理 #!/bin/bash # chkconfig: 2345 85 85 # description: sms- ...

最新文章

  1. 【每日一算法】搜索插入位置
  2. linux下使用ffmpeg命令录屏桌面
  3. 《Effective STL》学习笔记(第四部分)
  4. 鸟哥的Linux私房菜(基础篇)- 第八章、Linux 磁盘与文件系统管理
  5. 虚拟机安装以及PCL的配置(1)
  6. 《前端JavaScript重点》学习笔记 1-5
  7. 高精度加法(简明版C语言),高精度加法(简明版C语言)
  8. php如何在微信跳转支付宝支付,微信支付成功了怎么跳转到我指定的信息提示页? - 码支付...
  9. 中国水平板式过滤器行业市场供需与战略研究报告
  10. 删除误添加的本地github检查库文件
  11. 6.Linux/Unix 系统编程手册(上) -- 进程
  12. python java爬虫_java爬虫与python爬虫对比
  13. aqua datastudio配置
  14. 数字电子技术基础笔记
  15. 多功能的Silverlight控件User Interface Edition for Silverlight下载及详细介绍
  16. 540s inter 固件_Intel SSD Firmware Update Tool(英特尔ssd固件更新工具)下载 v2.1.6官方版...
  17. 《下学梯航》(全文)
  18. 阿里云网盘内测申请_最新阿里云网盘官方申请地址,哪里可以获得阿里网盘内测码?9月23日截至...
  19. 腾讯web引用skey g_tk bkn和日期显示分析
  20. Stable Diffsuion还能用来压缩图像?压缩率更高,清晰度超越JPEG等算法

热门文章

  1. Linux下全平台聊天工具,程序员的全平台聊天软件:Rocket.Chat
  2. 有哪些好用抠图软件?这几种抠图工具简单又高效
  3. 后台定时自动截图软件
  4. 黑白棋C\C++实现方式
  5. 2023年申请美国大学,需要SAT/ACT成绩吗?
  6. Windows Update MiniTool 微软系统手动更新补丁设置工具
  7. HBase学习之路(二):Java客户端的CRUD操作详讲
  8. openstack keystone整体架构与功能
  9. 泛函分析 第一章 度量空间
  10. 注意力机制 - 多头注意力