2016-06-08 28 views
0

我的程序的每個線程都有自己的日誌文件。在我的SIGHUP處理程序中,我想通知那些線程,當新的日誌消息到達時,他們需要重新打開它們的日誌文件。在多線程中延遲無效的東西

我想要一個基於標誌和計數器的無鎖解決方案。 (我有一個線程本地上下文結構用於其他目的,所以我可以在那裏添加新的字段)。

如果只是一個記錄線程,我會做:

static int need_reopen = 0; 

void sighancont(int signo) 
... 
    case SIGHUP: 
    need_reopen = 1; 
    break; 
... 
} 

void log(char *msg) { 
    if (need_reopen) { 
     need_reopen = 0; 
     reopen_log(); 
    } 
    ... 
} 

當然,如果有多個線程的日誌記錄,一個簡單的標誌不會做。我正在考慮這樣的事情:

static volatile int reopen_counter = 0; 

void sighancont(int signo) 
... 
    case SIGHUP: 
    __sync_fetch_and_add(&reopen_counter, 1); 
    break; 
... 
} 

void log(struct ctx_st *ctx, char *msg) { 
    int c = reopen_counter; 
    if (ctx->reopen_counter != c) { 
     ctx->reopen_counter = c; 
     reopen_log(); 
    } 
    ... 
} 

這種方式日誌記錄線程應該趕上全局計數器。如果程序多次收到SIGHUP,日誌文件將只能重新打開一次。

我看到唯一的方法來打破這個 - 發送SIGHUP〜40億次。

是否有更好的(但仍然很簡單)算法,例如:參考計數?

+1

您的代碼中有數據競爭。如果值不是原子的,則無法從多個線程讀取和修改相同的變量。 – SergeyA

+0

@SergeyA in sighancont()或log()?如果你的意思是2個concurren SIGHUPS,我可以和 – basin

+0

住在一起:) – SergeyA

回答

0

您的解決方案簡單高效。這是一個seqlock。

的幾個注意事項,從評論清除可能出現的混亂:

  1. 有沒有「原子變量」,但原子指令。 std :: atomic和friends,只是原子操作上的語法糖 - 你在那裏完全可以。
  2. 計數器不必是易失性的,但訪問必須是。當你寫atomic_read(x)你實際上說*(volatile int*)&x。 volatile限定符會導致從內存中完成對變量的所有訪問,而您不一定需要這樣做。 但是,在這裏,你完全沒問題,因爲你把變量讀入本地。
  3. 如果這是唯一一個作家(如果您刪除了volatile,請不要忘記將它改爲atomic_write),您可以非自動更新計數器。這將是一個非常小的性能改進。
  4. 這裏唯一的代價是在更新計數器後必須爲主存儲器訪問支付的日誌線程。您應該預計200個週期左右(其他NUMA節點上的x2)