一个用libcurl多线程下载断言错误问题的排查
某数据下载程序,相同版本的代码,在64位系统中运行正常,但在32位系统中概率性出现断言错误。一旦出现,程序无法正常继续,即使重启亦不行。从年前会上领导提出要追到根,跟到底,到年后的今天,经过排查、自测、试点,算是告一段落了。文中没有很难的技术问题,但过程还是值得记录的。本文从后来者角度总结一下解决问题的过程,同时给出相关测试代码。
由于本文没有技术含量,请谨慎按需阅读。
起因
当运维人员把出错的截图发给我时,我回想起1年半前的那个夏天,那天下午,运维人员将同一个错误截图给我,后来回退版本了,再也没出现了。这次,运维人员上报给了领导。会上我也答不出来为什么在32位系统上会报错,而在64位系统中却不行,也回答不了为什么回退版本又可以。下面这个错误,在笔记里躺了很久,现在又要翻出来,一点也没变化:
ath.c:193: _gcry_ath_mutex_lock: Assertion `*lock == ((ath_mutex_t) 0)' failed.
这是某个动态库报的断言错误,不是业务程序直接提示的。虚拟机模拟不出问题,现场机器没有gdb,也无法生成coredump,也没有pstrace,只能靠头脑分析排查了。
排查及解决
动态库定位
报错信息关键信息为ath.c、_gcry_ath_mutex_lock、ath_mutex_t。
经搜索,得到了一些有用的信息。
在libssh2官方网站上,找到一篇关于FIPS兼容性的帖子FIPS Compliance,提问者的错误是用sftp通过libcurl下载文件时产生的。路线和所遇问题几乎一样,出现断言错误的库为libgcrypt。在stackoverflow网站上找到这个帖子,帖子回答者提到:
Obviously you are using libgcrypt in there, either directly or through some library (liboauth?). Multithreaded use of gcrypt requires initialization, as documented at gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html - either you forgot it, or one of the maintainers of libraries you used did. Check the documentation… –
DevSolar
Dec 13, 2011 at 17:00
The problem was that more than one thread tries to get a http request at the same time. That’s not possible. So I used mutexes to avoid that.
使用libgcrypt时,在多线程中要初始化,至于初始化什么,怎么初始化,谁初始化,由于涉及libcurl->libssh2->libgcrypt等库,路径较深,鞭长莫及,代码人一声叹气。
关于ath.c断言语句的跟踪记录
前面定位到了libgcrypt库,在32位系统上用strings命令查找出错关键字:
strings /lib/i386-linux-gnu/libgcrypt.so.11.7.0 | grep "*lock =="
*lock == ((ath_mutex_t) 0)
*lock == ((ath_mutex_t) 1)strings /lib/i386-linux-gnu/libgcrypt.so.11.7.0 | grep "_gcry_ath_mutex_lock"
_gcry_ath_mutex_lock
是这个库无疑了。但11.7.0版本找不到ath.c文件。再在64位系统上查:
strings /lib64/libgcrypt.so.11.8.2 | grep "*lock =="
*lock == ((ath_mutex_t) 0)
*lock == ((ath_mutex_t) 1)strings /lib64/libgcrypt.so.11.8.2 | grep "_gcry_ath_mutex_lock"
_gcry_ath_mutex_lockfind /usr/ -name "libgcrypt*"
/usr/lib64/libgcrypt.so.11.8.2
/usr/lib64/libgcrypt.so.11
/usr/share/doc/libgcrypt-1.5.3
从信息中猜测,可能的版本是1.5.3。下载该版本解压,得到ath.c关键语句:

第193行,正是这多天魂牵梦萦想看到的语句。
但是,这只是知道了出错的地方而已,还不知道如何出错。
问题定位
从错误信息上看,和锁有关,进而推断和多线程有关。分析业务代码,的确有多线程下载。起初,跟踪线程内部的curl变量,但没有出现越界使用情况,都在相同内部线程完成了,每次下载,都用curl_easy_init初始化,最后用curl_easy_cleanup清理,通过打印跟踪可以确认这一点。
回到业务程序上。既然是多线程下载出错,就将多线程改成单线程,或者加上互斥锁,不让他们同时运行。这份代码比大锤的年龄还大,有一定的历史沉淀,且有较多名称相近的函数,类似于北湖北路,北湖南路,北湖东路等,不好改动。于是加上锁,再测试,没有发现问题。
解决方法
但依然没有找到原因。
访问libcurl官方示例页面,找到多线程例子,但参考价值不大,于是搭建sftp服务器,写了测试程序。经摸索,发现在一线程下载过程的同时另一线程也下载,则必然出错。开始时,下载的文件小,很快下载完毕,下载大文件时问题即刻暴露了。
回查业务代码,在两线程启动时,人工加了10秒的延时,当数据量较多大了,前一线程未下载完毕,后一线程启动,因此报错了。之前相安无事,应该是两线程下载的数据量并非都大,前一线程较快完成了下载。
但无论如何,在两线程之间加锁,的确能解决问题。
反馈
在试点跑了3天,暂时没有收到问题反馈。应该大概的确解决了这个问题。
小结
至于为何libcurl无法多线程下载,为何偏偏在32位系统上出现,其实还没有找到根本问题所在。多方测试,64位系统的确未发现有。于是在业务代码中通过宏定义限定只在32位系统才加锁。
附:自测程序
源码:
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <curl/curl.h>#define DOWNLOAD_LOCKstatic pthread_mutex_t connlock;void init_locks(void)
{pthread_mutex_init(&connlock, NULL);
}void kill_locks(void)
{pthread_mutex_destroy(&connlock);
}void my_locks(void)
{
#ifdef DOWNLOAD_LOCKpthread_mutex_lock(&connlock);
#endif
} void my_unlocks(void)
{
#ifdef DOWNLOAD_LOCKpthread_mutex_unlock(&connlock);
#endif
}//lldebug LoginStr aftp:123456 RemoteFile: sftp://192.168.168.88/DataStorary/Server/MyData/BigFile.dat LocalFile: /tmp/data/download/BigFile.datstatic size_t my_write(void *buffer, size_t size, size_t nmemb, void *stream)
{/* not interested in the downloaded bytes, return the size */ (void)buffer; /* unused */ (void)stream; /* unused */ return (size_t)(size * nmemb);
}void downloadFile(CURL *curl, const char *LoginStr, const char * RemoteFile, const char *LocalFile)
{//CURL *curl = InitCurl();if(curl == NULL){return;}curl_easy_setopt(curl, CURLOPT_USERPWD, LoginStr);curl_easy_setopt(curl, CURLOPT_URL, RemoteFile);curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_write);printf("lldebug %s().%d before curl_easy_perform ptr: %p\n", __func__, __LINE__, curl);CURLcode code = curl_easy_perform(curl);if(CURLE_OK != code){printf("curl_easy_perform failed, %d: %s\n", code, curl_easy_strerror(code));}
}static void *download_1(void *url)
{CURL *curl;const char* loginStr = "aftp:123456";//const char* rfile = "sftp://192.168.168.88/DataStorary/Server/MyData/smallfile.txt";const char* rfile = "sftp://192.168.168.88/DataStorary/Server/MyData/BigFile.dat";const char* lfile = "/tmp/file_1.txt";my_locks();printf("lldebug %s().%d begin++++++++++++++++++\n", __func__, __LINE__);curl = curl_easy_init();printf("lldebug %s().%d >>>>>>>> init curl ptr: %p\n", __func__, __LINE__, curl);downloadFile(curl, loginStr, rfile, lfile);printf("lldebug %s().%d <<<<<<<< download done curl ptr: %p\n", __func__, __LINE__, curl);curl_easy_cleanup(curl);printf("lldebug %s().%d end++++++++++++++++++\n", __func__, __LINE__);my_unlocks();
}static void *download_2(void *url)
{CURL *curl;const char* loginStr = "aftp:123456";const char* rfile = "sftp://192.168.168.88/DataStorary/Server/MyData/smallfile.txt";const char* lfile = "/tmp/file_2.txt";my_locks();printf("lldebug %s().%d begin------------------\n", __func__, __LINE__);curl = curl_easy_init();printf("lldebug %s().%d >>>>>>>> init curl ptr: %p\n", __func__, __LINE__, curl);downloadFile(curl, loginStr, rfile, lfile);printf("lldebug %s().%d <<<<<<<< download done curl ptr: %p\n", __func__, __LINE__, curl);curl_easy_cleanup(curl);printf("lldebug %s().%d end------------------\n", __func__, __LINE__);my_unlocks();
}int main(int argc, char **argv)
{pthread_t tid1;pthread_t tid2;init_locks();curl_global_init(CURL_GLOBAL_ALL);pthread_create(&tid1, NULL, download_1, NULL);usleep(1000);pthread_create(&tid2, NULL, download_2, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);kill_locks();curl_global_cleanup();return 0;
}
编译:
g++ test_thread.cpp -I/usr/local/curl/include -I/usr/include -lcurl
加锁情况下运行结果:
lldebug download_1().78 begin++++++++++++++++++
lldebug download_1().82 >>>>>>>> init curl ptr: 0x9216340
lldebug downloadFile().57 before curl_easy_perform ptr: 0x9216340
lldebug download_1().86 <<<<<<<< download done curl ptr: 0x9216340
lldebug download_1().91 end++++++++++++++++++
lldebug download_2().105 begin------------------
lldebug download_2().110 >>>>>>>> init curl ptr: 0x9216340
lldebug downloadFile().57 before curl_easy_perform ptr: 0x9216340
lldebug download_2().114 <<<<<<<< download done curl ptr: 0x9216340
lldebug download_2().118 end------------------
不加锁情况下运行结果:
lldebug download_1().78 begin++++++++++++++++++
lldebug download_1().82 >>>>>>>> init curl ptr: 0x9d37340
lldebug downloadFile().57 before curl_easy_perform ptr: 0x9d37340
lldebug download_2().105 begin------------------
lldebug download_2().110 >>>>>>>> init curl ptr: 0x9d4de18
lldebug downloadFile().57 before curl_easy_perform ptr: 0x9d4de18
a.out: ath.c:193: _gcry_ath_mutex_lock: Assertion `*lock == ((ath_mutex_t) 0)' failed.
Aborted
用gdb调试过程:
(gdb) r
Starting program: /home/latelee/libcurl_test/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/i686/cmov/libthread_db.so.1".
[New Thread 0xb769eb70 (LWP 7680)]
lldebug download_1().101 begin++++++++++++++++++
lldebug download_1().105 >>>>>>>> init curl ptr: 0x805a340
lldebug downloadFile().80 before curl_easy_perform ptr: 0x805a340
[New Thread 0xb6e9db70 (LWP 7681)]
lldebug download_2().128 begin------------------
lldebug download_2().133 >>>>>>>> init curl ptr: 0x8070e18
lldebug downloadFile().80 before curl_easy_perform ptr: 0x8070e18
a.out: ath.c:193: _gcry_ath_mutex_lock: Assertion `*lock == ((ath_mutex_t) 0)' failed.Program received signal SIGABRT, Aborted.
[Switching to Thread 0xb6e9db70 (LWP 7681)]
0xb7fe1424 in __kernel_vsyscall ()
(gdb) bt
#0 0xb7fe1424 in __kernel_vsyscall ()
#1 0xb7cf5941 in *__GI_raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#2 0xb7cf8d72 in *__GI_abort () at abort.c:92
#3 0xb7ceeb58 in *__GI___assert_fail (assertion=0xb7938626 "*lock == ((ath_mutex_t) 0)", file=0xb7938620 "ath.c", line=193, function=0xb7938674 "_gcry_ath_mutex_lock") at assert.c:81
#4 0xb78e9605 in ?? () from /lib/i386-linux-gnu/libgcrypt.so.11
#5 0xb792b02d in ?? () from /lib/i386-linux-gnu/libgcrypt.so.11
#6 0xb792c889 in ?? () from /lib/i386-linux-gnu/libgcrypt.so.11
#7 0xb792ae7d in ?? () from /lib/i386-linux-gnu/libgcrypt.so.11
#8 0xb78f82d9 in ?? () from /lib/i386-linux-gnu/libgcrypt.so.11
#9 0xb78f8a14 in ?? () from /lib/i386-linux-gnu/libgcrypt.so.11
#10 0xb78e078c in gcry_md_open () from /lib/i386-linux-gnu/libgcrypt.so.11
#11 0xb7c603b6 in ?? () from /usr/lib/i386-linux-gnu/libssh2.so.1
#12 0xb7c6f154 in ?? () from /usr/lib/i386-linux-gnu/libssh2.so.1
#13 0xb7c5a2c8 in ?? () from /usr/lib/i386-linux-gnu/libssh2.so.1
#14 0xb7c67108 in ?? () from /usr/lib/i386-linux-gnu/libssh2.so.1
#15 0xb7c67489 in ?? () from /usr/lib/i386-linux-gnu/libssh2.so.1
#16 0xb7c680db in libssh2_sftp_init () from /usr/lib/i386-linux-gnu/libssh2.so.1
#17 0xb7fa0688 in ?? () from /usr/lib/i386-linux-gnu/libcurl.so.4
#18 0xb7fa3f63 in ?? () from /usr/lib/i386-linux-gnu/libcurl.so.4
#19 0xb7fa4595 in ?? () from /usr/lib/i386-linux-gnu/libcurl.so.4
#20 0xb7f80380 in ?? () from /usr/lib/i386-linux-gnu/libcurl.so.4
#21 0xb7f8067a in ?? () from /usr/lib/i386-linux-gnu/libcurl.so.4
#22 0xb7f80732 in ?? () from /usr/lib/i386-linux-gnu/libcurl.so.4
#23 0xb7f8d255 in ?? () from /usr/lib/i386-linux-gnu/libcurl.so.4
#24 0xb7f8e033 in curl_easy_perform () from /usr/lib/i386-linux-gnu/libcurl.so.4
#25 0x08048acf in downloadFile(void*, char const*, char const*, char const*) ()
#26 0x08048c60 in download_2(void*) ()
#27 0xb7cb7c39 in start_thread (arg=0xb6e9db70) at pthread_create.c:304
#28 0xb7da1d4e in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:130
(gdb)
相关文章:
一个用libcurl多线程下载断言错误问题的排查
某数据下载程序,相同版本的代码,在64位系统中运行正常,但在32位系统中概率性出现断言错误。一旦出现,程序无法正常继续,即使重启亦不行。从年前会上领导提出要追到根,跟到底,到年后的今天&#…...
Docker的安装及MySQL的部署(CentOS版)
目录 1 前言 2 Docker安装步骤 2.1 卸载可能存在的旧版Docker 2.2 配置Docker的yum库 2.2.1 安装yum工具 2.2.2 配置Docker的yum源 2.3 安装Docker 2.4 启动和校验 2.5 配置镜像加速(使用阿里云) 2.5.1 进入控制台 2.5.2 进入容器镜像服务 2.5.3 获取指令并粘贴到…...
css 背景图片居中显示
background 简写 background: #ffffff url(https://profile-avatar.csdnimg.cn/b9abdd57de464582860bf8ade52373b6_misnice.jpg) center center / 100% no-repeat;效果如图:...
Python编程-如何轻松开启一个Web服务?
目录 前言 Flask:轻量级 Django:高级 Bottle:轻量级 Pyramid:灵活且可扩展 Tornado:可扩展、非阻塞 CherryPy:微型 轻量级的Web框架的选择 前言 在Python中开启一个Web服务有多种方法,选…...
鸡肋的Git
1.前言 对于大多数开发人员来说,我们大多数在学习或者工作过程中只关注核心部分,比如说学习Java,可能对于大多数人而言一开始都是从Java基础学起,然后408,Spring,中间件等,当你发现很多高深的技…...
iOS 中的 UITextField 如何设置才能只输入数字和小数点?
刚接触 iOS不久,接到一个iOS项目,其中有一个需求就是在一个 UITextField中只能输入数字和小数点,这个需求在Android中非常容易,只需要设置 <EditTextandroid:id"id/id_et_price"android:layout_width"match_par…...
阿珊详解Vue Router的守卫机制
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
python淘宝网页爬虫数据保存到 csv和mysql(selenium)
数据库连接设置(表和字段要提前在数据库中建好) # 数据库中要插入的表 MYSQL_TABLE goods# MySQL 数据库连接配置,根据自己的本地数据库修改 db_config {host: localhost,port: 3306,user: root,password: ma*****6,database: may2024,charset: utf8mb…...
云计算中仲裁节点和仲裁可用区介绍
在云计算中,仲裁是指当多个节点或实例之间发生争议或冲突时,由一个独立的第三方机构或节点来解决争议或冲突的过程。仲裁通常用于解决云计算中的资源分配、数据一致性、服务质量等问题。 仲裁的作用主要有以下几点: 1. 保证资源分配的公平性…...
Python的requests库发送HTTPS请求时,SSL证书验证的流程
建立连接:当你使用requests库发送HTTPS请求时,它会尝试与目标服务器建立安全的SSL连接。 获取服务器SSL证书:服务器会将自己的SSL证书发送给客户端(即你的请求)。 验证证书:requests库会验证服务器返回的…...
基于 HBase Phoenix 构建实时数仓(3)—— Phoenix 安装
目录 一、主机规划 二、Phoenix 安装 1. 解压、配置环境 2. 将 phoenix-server-hbase-2.5-5.1.3.jar 文件复制到 HBase 的 lib 目录中 3. 重启 HBase 集群 4. 安装验证 (1)连接 HBase (2)视图映射 (3…...
Python IDE
Python IDE 本文为大家推荐几款款不错的 Python IDE(集成开发环境),比较推荐 PyCharm,当然你可以根据自己的喜好来选择适合自己的 Python IDE。 PyCharm PyCharm 是由 JetBrains 打造的一款 Python IDE。 PyCharm 具备一般 Pyt…...
Vue3和Vue2的区别
Vue 3 是 Vue.js 的下一个主要版本,它引入了许多新特性和优化,与 Vue 2 相比有一些显著的区别。以下是一些主要的区别: 性能提升: Vue 3 提供了更快的虚拟 DOM,减少了渲染和更新时间。使用 Proxy 重写了响应式系统,使…...
【内推】新风口-大模型独角兽公司minimax
先上内推链接: MiniMax社招内推码: AK3XEJ6 投递链接: https://vrfi1sk8a0.jobs.feishu.cn/s/iFY5WFgE 岗位:前端、后端、算法,基础架构都有,大量hc 公司介绍: 国内同时拥有文本、语音、视觉三种基础大模型能力的创业…...
基于单片机的水平角度仪系统设计
目 录 摘 要 I Abstract II 引 言 1 1控制系统设计 3 1.1系统方案设计 3 1.2系统工作原理 4 2硬件设计 6 2.1单片机 6 2.1.1单片机最小系统 6 2.1.2 STC89C52单片机的性能 7 2.2角度采集电路 8 2.2.1 ADXL345传感器的工作原理 9 2.2.2 ADXL345传感器倾角测量的原理 9 2.2.3 AD…...
Haproxy 负载均衡集群
一. Haproxy 1. Haproxy 介绍 HAProxy 是法国开发者威利塔罗 (Willy Tarreau) 在2000年使用C语言开发的一个开源软件,是一款具备高并发(一万以上)、高性能的TCP和HTTP负载均衡器,支持基于cookie的持久性,自动故障切换,支持正则…...
微服务知识03
1、ES搜索引擎,高性能的分布式搜索引擎,底层基于Lucene 主要用于应用程序中的搜索系统 日志收集 2、基础概念 3、ES处理流程 5、下载中文分词器 Releases infinilabs/analysis-ik GitHub 6、分词模式 最细粒度拆分、智能分词 7、Elaticsearch配置流程 (1)把文件拖进…...
JPEG照片被误删除如何恢复?学会这个方法就够了
JPG/JPEG是一种后缀名为“.jpg”或“.jpeg”的图形格式。它是存储照片图像的常用格式,因此我们可以使用数码相机、手机或其他设备来获取大量的JPG/JPEG文件。有时,我们会遇到由于意外删除、格式化驱动器或其他未知原因导致 JPEG 文件丢失的情况。无论哪种…...
红黑树的学习
红黑树 红黑树出自一种平衡的二叉查找树,是计算机科学中中用到的一种数据结构 1972年出现,当时被称之为平衡二叉B树。后来,1978年被修改为如今的红黑树 他是一种特殊的二叉查找树,红黑树的每一个节点上都有存储表示节点的颜色 …...
C# OpenCvSharp DNN FreeYOLO 人脸检测
目录 效果 模型信息 项目 代码 下载 C# OpenCvSharp DNN FreeYOLO 人脸检测 效果 模型信息 Inputs ------------------------- name:input tensor:Float[1, 3, 192, 320] --------------------------------------------------------------- Outp…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...
【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...
高分辨率图像合成归一化流扩展
大家读完觉得有帮助记得关注和点赞!!! 1 摘要 我们提出了STARFlow,一种基于归一化流的可扩展生成模型,它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流(TARFlow&am…...
