You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

asctime(localtime)在gcc4.8.4正常gcc9.4.0多线程异常

问题原因说明
  • localtime和asctime都是C标准明确标注的非线程安全函数:两个函数内部都使用全局静态缓冲区存储返回结果,多线程并发调用时会出现缓冲区内容互相覆盖的问题,属于典型的未定义行为。
  • gcc 4.8.4环境下运行正常完全是巧合:旧版本配套的glibc中,这两个函数的静态缓冲区位置、程序编译后的内存布局恰好让并发覆盖操作没有破坏关键计算数据,属于未定义行为偶然表现为正常,不代表代码本身没有问题。
  • 切换到gcc 9.4.0后出错的核心原因:新版gcc配套的glibc升级后,调整了这两个时间函数的内部实现和静态缓冲区位置,多线程无锁并发调用时的缓冲区踩踏恰好破坏了存储计算结果的arr_DFT数组内存,直接导致最终写入文件的结果错误。
  • 从代码逻辑看,线程函数在pthread_mutex_unlock(&mutex)之后还有2次无锁的asctime(localtime(&ltime))调用,这部分代码是多线程并发执行的,是触发内存踩踏的核心位置。
通过Makefile临时修复的方法

可以通过添加编译宏的方式临时规避问题,但该方法依赖glibc的非标准扩展,不保证跨环境兼容,仅适合临时验证使用。
你当前的Makefile内容如下:

all: 
    gcc -Wall main.c -o hw5 -pthread -lm

clean:
    rm -f *o && rm -f hw5

添加-D_REENTRANT -D_GNU_SOURCE编译参数后,部分版本的glibc会自动将非线程安全的localtime、asctime调用重定向到可重入版本,临时解决并发踩踏问题,修改后的编译规则:

all: 
    gcc -Wall main.c -o hw5 -pthread -lm -D_REENTRANT -D_GNU_SOURCE

clean:
    rm -f *o && rm -f hw5
标准根治方案

不要依赖编译参数的非标准行为,直接将所有非线程安全的时间函数替换为POSIX标准定义的可重入版本,从代码层面彻底解决问题:

  • 用localtime_r替换localtime:该函数要求调用者自行传入struct tm结构体的存储地址,不使用全局静态缓冲区
  • 用asctime_r替换asctime:该函数要求调用者自行传入字符串存储缓冲区,不使用全局静态缓冲区

替换示例(以线程函数中的日志打印代码为例):
原问题代码:

sprintf(printBuffer,"%sThread %d has arrived the rendezvous point in %.2f seconds.\n",asctime(localtime(&ltime)),tempVal+1, time_spend);

修改为可重入版本:

struct tm tm_tmp;
char time_buf[26]; // asctime固定输出26字节长度(含结尾空字符)
localtime_r(&ltime, &tm_tmp);
asctime_r(&tm_tmp, time_buf);
sprintf(printBuffer,"%sThread %d has arrived the rendezvous point in %.2f seconds.\n",time_buf,tempVal+1, time_spend);

代码中所有调用时间函数的位置(主线程1处、线程函数3处)都需要按上述逻辑替换,替换后无需额外编译参数即可在所有POSIX兼容环境下保证线程安全,不会出现内存踩踏问题。

内容的提问来源于stack exchange,提问作者cBwavez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 01:51:25