The problem of multithreading of Lua OS. Date ()
The Lua version I used is 5.1.2. This problem is also estimated in other versions.
The OS. Date () function of Lua has a problem in multiple threads, even if every thread is an independent lua_state.
Cause:
Loslib of Lua. c, for OS. the implementation of the date function uses the localtime and gmtime functions, both of which are non-thread-safe. This means that using these two functions in multiple threads may cause a time error.
Therefore, calling OS. Date () in multiple threads contains security risks.
For example, in threadCode:
Local T = OS. Time ()-24*3600
Local ST1 = OS. date ("% Y % m % d", T)
Thread B:
Local T = OS. Time ()
Local st2 = OS. date ("% Y % m % d", T)
In this way, the above two pieces of code may encounter errors when different threads call frequently. The result of st2 is not necessarily the current time, but one day ago, the result page of ST1 may not be one day ago, but may be the current time, because the result is overwritten by the next call.
Solution:
1. Write a Lua extension by yourself and directly copy the OS _date implementation in the original loslib. C. Change the call localtime and gmtime to the thread-safe localtime_r and gmtime_r.
2. Modify the Lua source code and change the localtime and gmtime to the thread-safe localtime_r and gmtime_r.
This is a bug in Lua.
Attached the corrected OS _dateSource code:
Static void setfield (lua_state * l, const char *Key, int value) {lua_pushinteger (L, value); lua_setfield (L, - 2 , Key);} static void setboolfield (lua_state * L, const char * Key, int value ){ If (Value < 0 )/* Undefined? */ Return ;/* Does Not Set field */ Lua_pushboolean (L, value); lua_setfield (L, - 2 , Key);} static int OS _date (lua_state *L) {const char * S = lual_optstring (L, 1 , " % C " ); Time_t t = Lual_opt (L, (time_t) lual_checknumber, 2 , Time (null); struct TM tmx; struct TM * STM = & Tmx; char Buf [ 512 ]; File * F = NULL; int n = Lua_tonumber (L, 3 ); If (N = 1 ) {F = Fopen ( " C: \ osdate.txt " , " A + " ); If (! F) {printf ( " Open File osdate.txt Error " );} Else {Sprintf (BUF, " Now: % d, S = % s, t = % d, result = " , Time (null), S, T); fwrite (BUF, strlen (BUF ), 1 , F );}} If (* S = ' ! ' ) {/* UTC? */ Gmtime_r (& T, STM); s ++;/* Skip '!' */ } Else Localtime_r (& T, STM ); If (STM = NULL)/* invalid date? */ Lua_pushnil (L ); Else If (Strcmp (S, " * T " ) = 0 ) {Lua_createtable (L, 0 ,9 );/* 9 = Number of fields */ Setfield (L, " Sec " , STM-> Tm_sec); setfield (L, " Min " , STM-> Tm_min); setfield (L, " Hour " , STM->Tm_hour); setfield (L, " Day " , STM-> Tm_mday); setfield (L, " Month " , STM-> tm_mon + 1 ); Setfield (L, " Year " , STM-> tm_year + 1900 ); Setfield (L, " Wday " , STM-> tm_wday + 1 ); Setfield (L, " Yday " , STM-> tm_yday + 1 ); Setboolfield (L, " Isdst " , STM-> Tm_isdst );} Else {Char CC [ 3 ]; Lual_buffer B; CC [ 0 ] = ' % ' ; CC [ 2 ] = ' \ 0 ' ; Lual_buffinit (L, & B ); For (; * S; s ++ ){ If (* S! =' % ' | * (S + 1 ) = ' \ 0 ' )/* No conversion specifier? */ Lual_addchar (& B, * S ); Else {Size_t reslen; char buff [ 200 ];/* Shocould be big enough For Any Conversion Result */CC [ 1 ] = * (++ S); reslen = Strftime (buff, sizeof (buff), CC, STM); lual_addlstring (& B, buff, reslen );}} If (N = 1 ) {Fwrite (B. buffer, B. P -B. buffer, 1 , F); fwrite ( " \ N " , 1 ,1 , F);} lual_pushresult (& B );} If (N = 1 & F) {fclose (f); f = NULL ;} Return 1 ;}