lua的bug:lua的os.date()在多線程下的問題

來源:互聯網
上載者:User

lua的os.date()在多線程下的問題

我使用的lua版本是5.1.2,其他版本估計也有這個問題。
lua的os.date()函數在多線程下存在問題,即使是每個線程都是獨立的Lua_State.
原因:
lua的loslib.c中,對os.date函數的實現採用了localtime和gmtime這兩個函數,而這兩個函數都是非安全執行緒的,這意味著在多線程下使用這兩個函數有可能導致取時間錯誤.
所以無論如何,在多線程下調用os.date()都含有安全隱患.
例如,線上程A中有這樣的代碼:
local t = os.time() -24*3600
local st1 = os.date("%Y%m%d", t)
線程B中:
local t = os.time()
local st2 = os.date("%Y%m%d", t)

這樣,上面兩份代碼在不同線程頻繁調用的情況下就有可能出現錯誤,st2得到的結果未必是目前時間,而是一天前,而st1的結果頁未必是一天前,而有可能是目前時間,因為結果被後一次的調用覆蓋了。

修複方案:
1.自己寫個lua擴充,直接拷貝原來loslib.c中os_date的實現,將其中調用localtime和gmtime的地方改為安全執行緒的localtime_r 和gmtime_r即可
2.修改lua源碼,將localtime和gmtime的地方改為安全執行緒的localtime_r 和gmtime_r。
這個應該算是lua的一個bug了。

附上修正的os_date原始碼:

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];  /* should 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;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.