Linux的多线程(线程的创建,退出,取消请求,取消处理例程,线程属性的设置)
进程:是系统分配资源的最小单位,系统会为每一个进程分配一块独立的虚拟内存空间
线程:是系统调度的最小单位,系统不会为线程分配新的内存空间,但是线程也参与系统调度
cpu把时间片分给每一个进程,进程中的时间片再切分分给每一个线程,所以线程也会得到时间片,所以线程使系统调度的最小单位
线程的创建
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
pthread_t *thread //线程的tid
const pthread_attr_t *attr //线程的属性
void *(*start_routine) (void *) //线程的任务函数
void *arg //传递给任务函数的参数
编译时的时候记得添加 -lpthread
void *(*start_routine) (void *) 函数指针,指向需要执行的任务函数
任务函数返回值必须为 void *, 参数必须为 void *,回调函数
#include <stdio.h>
#include <pthread.h>// 任务线程
void *task1(void *arg)
{int j = 0;while (1){printf("j=%d\n", j++);}
}// 任务线程
void *task2(void *arg)
{int i = 0;while (1){printf("i=%d\n", i++);}
}// 任务线程
void *task3(void *arg)
{int k = 0;while (1){printf("k=%d\n", k++);}
}int main()
{pthread_t tid1;pthread_create(&tid1, NULL, task1, NULL);pthread_t tid2;pthread_create(&tid2, NULL, task2, NULL);pthread_t tid3;pthread_create(&tid3, NULL, task3, NULL);getchar(); //调用一个阻塞函数不让进程结束
}
线程传递参数
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>struct arg
{int a;double b;char str[1024];
} ;// 线程任务函数
void *task(void *arg)
{struct arg *p = arg;printf("整数1 %d\n", p->a);printf("浮点1 %f\n", p->b);printf("字符1 %s\n", p->str);}int main()
{struct arg arg = {15678, 156.78, "15678"};// 创建一个线程pthread_t tid;pthread_create(&tid, NULL, task, &arg); //&arg是线程函数中的参数sleep(1);printf("整数2 %d\n", arg.a);printf("浮点2 %f\n", arg.b);printf("字符2 %s\n", arg.str);getchar(); //阻塞主进程
}
线程退出
退出当前线程
#include <pthread.h>
void pthread_exit(void *retval);
参数retval是线程的返回值,对应线程执行函数的返回值。若线程没有数据可返回则可写成NULL。
pthread_exit()用法可参照exit()
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void *task(void *arg) // 子线程
{int i = 0;while (1){printf("i=%d\n", i++);sleep(1);if (i == 10){printf("退出子线程\n");pthread_exit(NULL); // 退出子线程}}
}int main() // main 主线程
{// 创建线程线程pthread_t tid;pthread_create(&tid, NULL, task, NULL);// 默认情况,主函数结束,那么进程也会结束,所有线程都会死亡!printf("退出主线程\n");pthread_exit(NULL); // 退出 main主函数线程。只是结束线程,进程并未结束// 所以就算主线程结束了子线程也还是会继续运行
}
回收一个线程资源,主线程阻塞等待子线程结束,然后回收子线程资源
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval)
thread: 需要回收资源的线程tid
retval:线程的退出参数,参数同上填NULL即可
通过阻塞等待线程执行完回收资源
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>// 任务线程
void *task(void *arg)
{int i = 0; // 局部变量,属于线程的栈空间while (1){printf("线程正在执行任务 &i=%p %d\n", &i, i++);if (i == 10){pthread_exit(&i); // 退出线程}sleep(1);}
}int main()
{// 1.创建一个线程pthread_t tid;pthread_create(&tid, NULL, task, NULL);printf("等待线程结束回收资源\n");void *p = NULL;pthread_join(tid, &p); // 一直阻塞等待线程退出 ! 回收线程的栈空间printf("线程结束 退出参数:%p\n", p);printf("退出参数 %d\n", *((int *)p)); // 访问已经回收后的内存资源,非法访问!!exit(0);}
如果没有pthread_join那么线程根本不会执行完,直接在主线程中就exit(0)退出进程了
线程取消
发送一个取消命令给线程
#include <pthread.h>
int pthread_cancel(pthread_t thread);
thread:需要取消的线程 tid
成功返回 0,失败将返回错误码
pthread_self() 返回主线程的线程号tid
线程取消请求
当线程收到一个取消请求时,他将会如何表现取决于两个东西:一是当前的取消状态,二是当前的取消类型。
线程的取消状态很简单--分别是PTHREADCANCEL ENABLE和 PTHREAD CANCEL DISABLE,前者是缺省的,代表线程可以接受取消请求,后者代表关闭取消请求,不对其响应。
而在线程接受取消请求的情况下,如何停下来又取决于两种不同的响应取消请求的策略一延时响应和立即响应,当采取延时策略时,线程并不会立即退出,而是要遇到所谓的“取消点”之后,才退出。而“取消点”,指的是一系列指定的函数。
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);//开启或关闭取消请求
state : 新的取消状态 PTHREAD_CANCEL_ENABLE 开启
PTHREAD_CANCEL_DISABLE 关闭
oldstate:原来的状态
int pthread_setcanceltype(int type, int *oldtype); //设置取消类型
type:取消类型 PTHREAD_CANCEL_DEFERRED 延时取消 (默认类型)
PTHREAD_CANCEL_ASYNCHRONOUS 立即取消
返回值:成功 0
失败errno
设置线程取消请求demo:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
// 任务线程
void *task(void *arg)
{// 关闭取消请求pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);int i = 0;while (1){printf("线程正在执行任务 %d\n", i++);if (i == 10){printf("执行完毕\n");break;}sleep(1);}// 开启取消请求pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);while (1){printf("线程正在运行\n");sleep(1);}
}int main()
{// 1.创建一个线程pthread_t tid;pthread_create(&tid, NULL, task, NULL);while (1){printf("输入任意键取消线程\n");getchar();pthread_cancel(tid);}
}
在关闭线程取消请求之后,线程无法被取消,只有在重新打开线程取消请求之后的第二个循环中才能通过pthraed_cancel取消线程
线程取消处理函数
由于线程任何时刻都有可能持有诸如互斥锁、信号量等资源,一旦被取消很有可能导致别的线程出现死锁,因此如果一条线程的确可能被取消,那么在被取消之前必须使用以下API来为将来可能出现的取消请求注册“处理例程”,让这些例程自动释放持有的资源。
注册一个取消处理函数,当线程被取消时,会去执行该函数
#include <pthread.h>
void pthread_cleanup_push(void (*routine)(void *), void *arg);
routine: 函数指针,指向线程被取消后需要执行的函数
arg:传递给取消处理函数使用的参数
void pthread_cleanup_pop(int execute);
execute: 0 不执行,线程正常结束不执行取消处理函数
1 执行,线程正确结束执行取消处理函数(只要线程被取消,都会执行取消处理函数)
pthread_cleanup_push必须与 pthread_cleanup_pop 一起使用,且在同一个作用域中
注册一个线程取消处理函数demo:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
FILE *fp = NULL;void clear_task(void *arg)
{printf("线程被取消,执行取消处理函数\n");fclose(fp); // 关闭文件,刷新缓存
}void *task(void *arg)
{int i = 0;// 打开文件fp = fopen("test.txt", "w+");// 注册一个取消处理函数pthread_cleanup_push(clear_task, NULL);while (1) // 正在运行的时候被别人取消了{fputc('Q', fp); // 写入文件printf("线程正在写入数据到文件中\n");sleep(1);i++;if (i == 10){break;}}//pthread_cleanup_pop(0); // 正常结束的时候,不执行pthread_cleanup_pop(1); //正常结束的时候, 执行printf("线程正常结束\n");fclose(fp); // 关闭文件,刷新缓存
}int main()
{// 1.创建一个线程pthread_t tid;pthread_create(&tid, NULL, task, NULL);while (1){printf("按任意键取消线程\n");getchar();pthread_cancel(tid);}return 0;
}
在这段代码中当pthread_cleanup_pop中的值为1时,线程正常结束时也会执行clean_task中的函数,如果excute的值为0的话,那么只有在线程执行的过程中被打断会执行clean_task函数。
线程属性的设置
线程相关的api


查看系统的资源
loading@DESKTOP-R0NLPTR:~$ ulimit -a
real-time non-blocking time (microseconds, -R) unlimited
core file size (blocks, -c) 0 #core文件的最大值为100 blocks。
data seg size (kbytes, -d) unlimited #进程的数据段可以任意大。
scheduling priority (-e) 0 #调度优先级
file size (blocks, -f) unlimited #文件可以任意大。
pending signals (-i) 25348 #最多有25348个待处理的信号。
max locked memory (kbytes, -l) 64 #一个任务锁住的物理内存的最大值为32KB。
max memory size (kbytes, -m) unlimited #一个任务的常驻物理内存的最大值。
open files (-n) 1024 #一个任务最多可以同时打开1024的文件。
pipe size (512 bytes, -p) 8 #管道的最大空间为4096字节。
POSIX message queues (bytes, -q) 819200 #POSIX的消息队列的最大值为819200字节。
real-time priority (-r) 0
stack size (kbytes, -s) 8192 #进程的栈的最大值为10240字节。
cpu time (seconds, -t) unlimited #进程使用的CPU时间。
max user processes (-u) 25348 #当前用户同时打开的进程(包括线程)的最大个数为25348。
virtual memory (kbytes, -v) unlimited #没有限制进程的最大地址空间。
file locks (-x) unlimited #所能锁住的文件的最大个数没有限制。
设置线程属性的流程
1、初始化线程属性
2、设置线程属性
3、根据设置的线程属性创建线程
4、销毁线程和属性
线程属性也是线程创建的第二个参数
线程属性的创建和销毁
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
线程属性的设置
#include <pthread.h>
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); //设置栈大小
int pthread_attr_getstacksize(const pthread_attr_t *attr,
size_t *stacksize);//获取栈大小
线程栈空间的设置
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void *task(void *arg)
{int i = 0;while (1){printf("线程正在运行 %d\n", i++);sleep(1);if (i == 10){// 退出线程pthread_exit(NULL);}}
}int main()
{// 初始化一个线程属性pthread_attr_t attr;pthread_attr_init(&attr);int n;printf("请输入需要设置的线程大小\n");scanf("%d", &n);// 设置线程属性//分配的栈空间必须比系统分配最小的栈空间要大,//本机最小栈空间为16384,下文给出查看最小分配栈空间办法int size = 16384 + n;// int size = 1024;pthread_attr_setstacksize(&attr, size);// 根据当前的栈大小创建线程pthread_t tid;pthread_create(&tid, &attr, task, NULL);// 获取当前线程的栈大小size_t stacksize = 0;pthread_attr_getstacksize(&attr, &stacksize); // 获取栈大小printf("当前线程的栈大小 %ld\n", stacksize);// 回收线程资源pthread_join(tid, NULL);// 销毁属性pthread_attr_destroy(&attr);
}
获取本机当前需要分配的最小栈空间
stack_min.c
#include <stdio.h>
#include <limits.h>int main()
{printf("%d\n", PTHREAD_STACK_MIN);
}
可以看到本机的栈空间为16384
loading@DESKTOP-R0NLPTR:~/ gcc stack_min.c && ./a.out
16384
线程分离属性设置
一条线程如果是可接合的,意味着这条线程在退出时不会自动释放自身资源,而会成为僵尸线程,同时意味着该线程的退出值可以被其他线程获取。
因此,如果不需要某条线程的退出值的话,那么最好将线程设置为分离状态,以保证该线程不会成为僵尸线程。
#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
detachstate: 线程分离属性 PTHREAD_CREATE_DETACHED 分离状态,自动回收资源
PTHREAD_CREATE_JOINABLE 结合状态,手动回收资源
注意:当一个线程设置为分离属性后,pthread_join 函数失效了! 因为该线程已经无需手动回收资源!没有返回值的函数是宏定义函数!
设置分离属性自动回收资源demo:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void *task(void *arg)
{int i = 0;while (1){printf("线程正在运行 %d\n", i++);sleep(1);if (i == 10){// 退出线程pthread_exit(NULL);}}
}int main()
{// 初始化一个线程属性pthread_attr_t attr;pthread_attr_init(&attr);// 设置线程分离属性pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);// 根据当前的栈大小创建线程pthread_t tid;pthread_create(&tid, &attr, task, NULL);printf("等待线程结束\n");// 回收线程资源pthread_join(tid, NULL); // 失效,因为线程自己回收资源!printf("线程资源回收\n");// 销毁属性pthread_attr_destroy(&attr);getchar();}
主线程与子线程自动分离,子线程结束后,资源自动回收
#include <pthread.h>
int pthread_detach(pthread_t thread)
pthread_join()函数的替代函数,可回收创建时detachstate属性设置为PTHREAD_CREATE_JOINABLE的线程的存储空间。该函数不会阻塞父线程。pthread_join()函数用于只是应用程序在线程tid终止时回收其存储空间。如果tid尚未终止,pthread_detach()不会终止该线程
快速回收资源demo:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void *task(void *arg)
{int i = 0;while (1){printf("线程正在运行 %d\n", i++);sleep(1);if (i == 10){// 退出线程pthread_exit(NULL);}}
}int main()
{// 根据当前的栈大小创建线程pthread_t tid;pthread_create(&tid, NULL, task, NULL);// 快速设置分离属性pthread_detach(tid);printf("等待线程结束\n");// 回收线程资源pthread_join(tid, NULL); // 失效,因为线程自己回收资源!printf("线程资源回收\n");getchar();
}
相关文章:
Linux的多线程(线程的创建,退出,取消请求,取消处理例程,线程属性的设置)
进程:是系统分配资源的最小单位,系统会为每一个进程分配一块独立的虚拟内存空间 线程:是系统调度的最小单位,系统不会为线程分配新的内存空间,但是线程也参与系统调度 cpu把时间片分给每一个进程,进程中的时间片再切分分给每一个线程,所以线程也会得到…...
git 本地代码关联远程仓库并推送
初始化代码仓库 如果你的本地项目还没有使用Git管理,首先需要在项目根目录下初始化一个Git仓库 git init添加远程仓库地址 使用 git remote add 命令添加远程仓库 git remote add origin https://github.com/username/repository.git获取远程分支信息 使用 git…...
推荐一个可以把PDF样本册转换为翻页电子书的网站
随着互联网的普及,越来越多的企业和个人开始意识到线上展览的重要性。如何将实体样本册转化为线上版本,让更多人了解和欣赏自己的产品与服务? 一、网站简介 这款PDF样本册免费上传网站名为“FLBOOK”,致力于为广大用户提供便捷…...
【Linux 23】线程池
文章目录 🌈 一、线程池的概念🌈 二、线程池的应用场景🌈 三、线程池的实现 🌈 一、线程池的概念 线程池 (thread pool) 是一种利用池化技术的线程使用模式。 虽然创建线程的代价比创建进程的要小很多,但小并不意味着…...
Rust SQLite 跨平台使用
引言 Rust因其内存安全性和高性能受到越来越多开发者的青睐。在许多项目中,SQLite作为一种轻量级的嵌入式数据库,与Rust的结合为跨平台应用程序提供了强大的支持。本文将详细探讨Rust如何实现跨平台功能,如何在不同平台上使用Rust库…...
docker运行arm64架构的镜像、不同平台镜像构建
背景 Docker 允许开发者将应用及其依赖打包成一个轻量级、可移植的容器,实现“一次构建,到处运行”的目标。然而,不同的操作系统和硬件架构对容器镜像有不同的要求。例如,Linux 和 Windows 系统有不同的文件系统和系统调用&#…...
vue基于Spring Boot框架的高校实验室预约管理系统
目录 毕设制作流程功能和技术介绍系统实现截图开发核心技术介绍:使用说明开发步骤编译运行代码执行流程核心代码部分展示可行性分析软件测试详细视频演示源码获取 毕设制作流程 (1)与指导老师确定系统主要功能; (2&am…...
Linux中find命令详解
记录linux中find命令的详细用法。 文章目录 find命令简介基本语法常用选项-name-iname-type-size-mtime,-atime,-ctime-perm-user-group-delete-exec-printand or find --help find命令简介 find 是一个搜索目录树以查找一个文件或一组文件的程序。它遍历目录树并报告与用户规…...
无水印短视频素材下载网站有哪些?十个高清无水印视频素材网站分享
你知道怎么下载无水印视频素材吗?今天小编就给大家推荐十个高清无水印视频素材下载的网站,如果你也是苦于下载高清无水印的短视频素材,赶紧来看看吧~ 1. 稻虎网 首推的是稻虎网。这个网站简直就是短视频创作者的宝库。无论你需要…...
SpringBoot+Activiti7工作流入门实例
目录 文章目录 目录准备Activiti建模工具1、BPMN-js在线设计器1.1 安装1.2 使用说明1.3运行截图2、IDEA安装Activiti Designer插件2.1安装插件2.2 设置编码格式防止中文乱码2.3 截图简单工作流入门实例1. 新建Spring Boot工程2. 引入Activiti相关依赖添加版本属性指定仓库添加依…...
Azure OpenAI检索增强微调:使用 GPT-4o 对 GPT-4o mini 进行微调,以适应特定领域的应用
定制是关键! 生成式人工智能对企业最有影响力的应用之一是创建自然语言界面,这些界面经过定制,可以使用特定领域和用例数据来提供更好、更准确的响应。这意味着回答有关特定领域的问题,例如银行、法律和医疗领域。 我们经常谈…...
ISP Pipeline
系列文章目录 文章目录 系列文章目录前言一、RAW域二、RGB域三、YUV域总结 前言 一、RAW域 黑电平校正(BLC)数字增益调整(DGain)自动白平衡(AWB)局部色调映射(LTM)坏点修复…...
< IDE编程环境配置>
IDE编程环境配置 LIB,DLL区别 我们在写项目时会链接(调用)第3方库,或者比如在vs的解决方案solution创建项目project时,不仅可以开发可执行程序exe(可单独运行)(windows/控制台 应用…...
Golang | Leetcode Golang题解之第448题找到所有数组中消失的数字
题目: 题解: func findDisappearedNumbers(nums []int) (ans []int) {n : len(nums)for _, v : range nums {v (v - 1) % nnums[v] n}for i, v : range nums {if v < n {ans append(ans, i1)}}return }...
【Spring Boot 入门三】Spring Boot与数据库集成 - 构建数据驱动的应用
一、引言 在之前的文章中,我们已经对Spring Boot有了初步的认识,了解了如何构建第一个Spring Boot应用,以及如何通过配置文件来掌控应用的设置。这些知识为我们进一步探索Spring Boot与数据库的集成奠定了坚实的基础。 数据库是现代应用的核…...
Web 服务器与动态脚本语言通信的接口协议有哪些
Web 服务器与动态脚本语言通信的接口协议主要有以下几种: 一、FastCGI(Fast Common Gateway Interface) 特点:使用持久进程处理请求,减少了进程启动和关闭的开销,提高了性能和可扩展性。多个请求可由同一个…...
ESXI识别服务器磁盘,虚拟机显示无效
ESXI识别服务器磁盘,虚拟机显示无效 系统意外断电识别不到磁盘的情况下可以管理-》硬件-》搜索磁盘名称,选择切换直通,则虚拟机正常。...
【C++】 vector 迭代器失效问题
【C】 vector 迭代器失效问题 一. 迭代器失效问题分析二. 对于vector可能会导致其迭代器失效的操作有:1. 会引起其底层空间改变的操作,都有可能是迭代器失效2. 指定位置元素的删除操作--erase3. Linux下,g编译器对迭代器失效的检测并不是非常…...
【Spring基础3】- Spring的入门程序
目录 3-1 Spring的下载3-2 Spring的 jar 包3-3 第一个 Spring程序第一步:添加spring context的依赖,pom.xml配置如下第二步:添加junit依赖第三步:定义bean:User第四步:编写spring的配置文件:bea…...
golang学习笔记22-面向对象(四):接口【重要】
本节也是GO核心部分,很重要。 注:由于导包语句已经在19讲(笔记19:面向对象的引入)展示过了,所以这里就不展示了。 一、定义与实现 (1)接口中可以定义一组方法,但不需要实现,不需要…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
【PX4飞控】mavros gps相关话题分析,经纬度海拔获取方法,卫星数锁定状态获取方法
使用 ROS1-Noetic 和 mavros v1.20.1, 携带经纬度海拔的话题主要有三个: /mavros/global_position/raw/fix/mavros/gpsstatus/gps1/raw/mavros/global_position/global 查看 mavros 源码,来分析他们的发布过程。发现前两个话题都对应了同一…...
项目进度管理软件是什么?项目进度管理软件有哪些核心功能?
无论是建筑施工、软件开发,还是市场营销活动,项目往往涉及多个团队、大量资源和严格的时间表。如果没有一个系统化的工具来跟踪和管理这些元素,项目很容易陷入混乱,导致进度延误、成本超支,甚至失败。 项目进度管理软…...
LTR-381RGB-01RGB+环境光检测应用场景及客户类型主要有哪些?
RGB环境光检测 功能,在应用场景及客户类型: 1. 可应用的儿童玩具类型 (1) 智能互动玩具 功能:通过检测环境光或物体颜色触发互动(如颜色识别积木、光感音乐盒)。 客户参考: LEGO(乐高&#x…...
AWSLambda之设置时区
目标 希望Lambda运行的时区是东八区。 解决 只需要设置lambda的环境变量TZ为东八区时区即可,即Asia/Shanghai。 参考 使用 Lambda 环境变量...
