2009-08-26 22 views
9

對於特定於類的new_handler實現,我在書「effective C++」中遇到以下示例。這看起來在多線程環境中的問題,我的問題是如何在多線程環境中實現類特定的new_handler?使用類特定的set_new_handler

void * X::operator new(size_t size) 
{ 
    new_handler globalHandler =    // install X's 
    std::set_new_handler(currentHandler); // handler 
    void *memory; 
    try {          // attempt 
     memory = ::operator new(size);   // allocation 
    } 
    catch (std::bad_alloc&) {     // restore 
     std::set_new_handler(globalHandler);  // handler; 
     throw;         // propagate 
    }           // exception 
    std::set_new_handler(globalHandler);  // restore 
               // handler 
    return memory; 
} 

回答

4

你說得對。這可能不是線程安全的。你可能要考慮一種替代方法就像使用nothrow version of new代替:

void* X::operator new(std::size_t sz) { 
    void *p; 
    while ((p = ::operator new(sz, std::nothrow) == NULL) { 
    X::new_handler(); 
    } 
    return p; 
} 

這將導致每當內存分配失敗時要調用的類特定的處理程序。我不會這樣做,直到你真正瞭解所有圍繞超載operator new的頭疼。特別是閱讀Herb Sutter的兩篇文章To New,引發異議,Part 1Part 2。有趣的是,他說要避免nothrow版本...嗯。

0

C++不知道線程是什麼。你必須轉向你的編譯器/ C++標準庫/操作系統/線程庫手冊,以確定一個線程安全的方式來做到這一點,或者甚至可能。我建議新的處理程序應該可以在應用程序中保持一致。這不是一個非常靈活的機制,或許您的需求會更好地服務於分配器或工廠(功能)?你想在自定義新處理程序中做什麼?

0

也許你看錯了方向。我不認爲有什麼辦法可以限制整個應用程序的內存分配(因爲大部分的內存分配可能不在你的代碼之內),所以最好的方法是控制你的可執行程序 - 即實現的處理程序。

設置處理程序以在程序開始時調用「OutOfMemoryHandler」類的實例(調用它將會),並具有其默認行爲來調用現有處理程序。當您想要添加類特定的處理時,使用您最喜愛的C++技術爲您的OutOfMemoryHandler添加一個行爲來實現動態行爲。

該解決方案應該在單線程環境中運行良好,但會在多線程環境中失敗。要使其在多線程環境中工作,您需要調用者通知處理程序對象它正在特定線程中工作;傳遞線程id與類將是一個很好的方法來做到這一點。如果處理程序被調用,那麼它會檢查線程ID並根據關聯的類確定要執行的行爲。當new()調用完成時,只需取消註冊thread-id以確保正確的默認行爲(就像您在重置默認處理程序時一樣)。