我正在研究C时间库的例程,因为我需要一种方法来跟踪程序日志文件的时间。我发现这样做的方法是拥有一个time_t
对象,该对象只保留自1970年1月1日00:00 UTC以来的秒数。然后,我将此time_t
对象解析为localtime(time_t* argument)
例程,该例程将返回指向tm
结构的指针。后者将把时间保留在一个更复杂的结构中,从1970年1月1日开始,用几秒,几个月,几天,几小时等来换算时间。这个tm
结构指针最终可以被{{1返回一个人类友好的日志时间(即2016年9月7日星期三13:45:23)。
我的问题是关于asctime(strcut tm* argument)
对象。正如我们在Cplusplus的示例代码中看到的那样,永远不会声明struct tm
对象,只有指针。意味着此对象在其他地方声明,我们只是访问它。参考链接本身表明:
struct tm
那么,谁创建了"The function also accesses and modifies a shared internal object,
which may introduce data races on concurrent calls to gmtime and
localtime. Some libraries provide an alternative function that avoids
this data race: localtime_r (non-portable)."
对象?它是第一次加载时是C时间库吗?这意味着加载库的第一个进程会声明对象,而所有其他进程只会与已声明的对象共享此库?为了避免那些Data Races问题,为每次调用创建一个新的struct tm
对象并返回指向它的指针,以便每个程序都有自己的结构,这不是更好吗?
对于使用Ctime的每个程序,可能有struct tm
而不是单个结构?有没有这样做的原因呢?
最后,使用C时间库struct tm MyProgramStruct; localtime(&Rawtime, &MyProgramStruct);
例程是不好的做法,因为程序不同步可能会导致输出错误?
链接中的示例代码:
localtime
答案 0 :(得分:4)
那么,谁创建了struct tm对象?是第一次加载C时间库吗?
根据localtime()
函数的文档,它返回一个指向静态分配的结构的指针。该结构属于C库;该函数提供了一个指向它的指针。它的确切位置的精细细节以及它的存储时间和方式的确切分配并不重要,并且可能因实施而异。您只需要了解同一进程的不同调用,并提供指向同一结构的指针。
这意味着加载库的第一个进程会声明对象,而所有其他进程只会与已声明的对象共享此库吗?
没有。您不必担心进程之间共享的结构,只需要在多个调用之间以及同一进程中的多个线程之间共享它。
为了避免那些Data Races问题,为每次调用创建一个新的struct tm对象并返回一个指向它的指针,以便每个程序都有自己的结构,会不会更好?对于使用Ctime的每个程序,可能有
struct tm MyProgramStruct; localtime(&Rawtime, &MyProgramStruct);
而不是单个结构?这样做的原因是什么呢?
同样,它不是一个跨进程问题,只是一个内部进程问题,这仍然很糟糕。是的,这个问题可以通过不共享结构来解决,这是区分函数localtime_r()
的区别所在。但是现有的函数不能改变以做同样的事情,因为这将为用户引入一个新的要求来释放提供的结构。
localtime()
的设计师希望使其易于使用,实际上只要您不与共享数据问题发生冲突。如果您的程序是单线程的,那么您可以相当容易地避免它。 localtime()
不是唯一具有此类问题的标准库函数。
最后,使用C时间库
localtime
例程是不好的做法,因为程序不同步可能会导致输出错误?
不是因为这个原因,不,因为没有跨进程问题。当您使用localtime()
和其他具有类似静态存储功能时,做需要注意,例如strtok()
。但您可以逐个程序地判断是否存在任何数据竞争 - 您不必担心来自未指定的其他程序的干扰。