工作中遇到的问题:设备需要上传图片到云平台,在上传失败时会进行重传,但在重传时却找不到对应的文件(文件命令方式为:日期_时间_id.jpg,如:2021-04-19_09_48_33_123456.jgp,文件名中的id是唯一的)。文件名中的日期-时间是从数据库里取出,然后再组成文件名字符串,再取文件进行上传。问题就是:id跟上传失败的文件id一样,但日期时间却不一样,本应该取上传失败的文件进行重传,结果文件名不一样导致找不到文件。
原因:在从数据库中取得文件信息后,信息里有文件的时间戳,当用localtime解析出struck tm结构体信息得出年、月、日、时、分、秒,此时有其他线程调用了localtime,你所解析出来的时期、时间并不是你想要的。
解决:调用localtime_r线程安全函数。
问题的原因是,localtime是一个不可重入函数,因为它返回的是一个局部静态变量,是线程不安全函数。线程安全函数为:localtime_r
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
void makeTimeStr(struct tm *pTm, char *outStr, int len);
void *threadProc(void *param);
int main()
{
pthread_t id;
char out_data_name[512] = {0};
char tmpStr[512] = {0};
//解析出当前时间结构体struct tm日期、时间信息
time_t t_now = time(NULL);
struct tm *tm_now = localtime(&t_now);
//在其他线程中调用localtime
pthread_create(&id, NULL, threadProc, NULL);
sleep(3);
//即使使用刚才的tm_now结构体,得到的也是最后一次localtime返回的值
makeTimeStr(tm_now, out_data_name, 512);
printf("name1: %s\n", out_data_name);
pthread_join(id, NULL);
return 0;
}
void makeTimeStr(struct tm *pTm, char *outStr, int len)
{
snprintf(outStr, len, "device/%s/%04d%02d%02d/channel_%d/%04d-%02d-%02d_%02d-%02d-%02d.json",
"84E0F4224C348004",
(1900 + pTm->tm_year),
(1 + pTm->tm_mon),
pTm->tm_mday,
0,
(1900 + pTm->tm_year),
(1 + pTm->tm_mon),
pTm->tm_mday,
pTm->tm_hour,
pTm->tm_min,
pTm->tm_sec
);
}
void *threadProc(void *param)
{
//解析指定时间戳得出日期、时间信息
time_t tt = 1615971890;
struct tm *tm_later = localtime(&tt);
return NULL;
}
运行结果 :
当调用localtime时,你不知道有没有其他进程或线程也在调用,即使调用完就使用,也不能保证在使用时没有有其他线程在调用localtime,此时得到的日期时间肯定不是想要的。正常的用法是用localtime_r函数。