2010-06-09 48 views
2

我在使用pthreads程序時發生偶然性崩潰,可能與線程在數據上的運行方式有關,因此我有一些關於如何使用線程和內存佈局進行編程的基本問題:如何使用C++&Pthreads安全地操作線程中的參數?

假設公共類函數對某些字符串執行某些操作,並將結果作爲字符串返回。該函數的原型可能是這樣的:

std::string SomeClass::somefunc(const std::string &strOne, const std::string &strTwo) 
{ 
//Error checking of strings have been omitted 
std::string result = strOne.substr(0,5) + strTwo.substr(0,5); 
return result; 
} 
  1. 它是正確的假設,字符串,是動態的,存儲在堆上,但是這個字符串的引用堆棧在運行時分配?

堆棧:[某些MEM地址]指針地址 到該字符串是在堆上

堆:分配用於其 可以增大或縮小初始串[部份MEM地址]存儲器

爲了使函數線程安全的,功能與下面的互斥體(被聲明爲私有的「SomeClass的」)延長鎖定:

std::string SomeClass::somefunc(const std::string &strOne, const std::string &strTwo) 
{ 
pthread_mutex_lock(&someclasslock); 

//Error checking of strings have been omitted 
std::string result = strOne.substr(0,5) + strTwo.substr(0,5); 

pthread_mutex_unlock(&someclasslock); 

return result; 
} 
  • 這是鎖定向下字符串(三個)正在進行的操作的安全的方式,或者可能一個線程調度器在下列情況下被停止,這我會假設會弄亂預期的邏輯:

    a。調用該函數之後,參數strOne & strTwo已在函數在堆棧中的兩個引用指針中設置,調度程序爲該線程取消處理時間,並讓新線程進入,從而覆蓋該引用指向函數的指針,然後再由調度程序停止,讓第一個線程回來?

    b。可以在相同的發生與「結果」的字符串:第一個字符串構建的結果,解鎖互斥量,但在此之前返回調度在另一個線程執行它的所有工作,覆蓋結果讓等

  • 或者當另一個線程正在執行它的任務時,引用參數/結果字符串被壓入堆棧?

  • 是在線程這樣做,和「返回」的結果的安全/正確的方式,傳遞給將要填充的結果,而不是一個字符串的引用:

    空隙SomeClass的:: somefunc(常量的std :: string & strOne,常量的std :: string & strTwo,的std :: string結果) { 的pthread_mutex_lock(& someclasslock);

    //錯誤檢查字符串已被省略 result = strOne.substr(0,5)+ strTwo。SUBSTR(0,5);

    pthread_mutex_unlock(& someclasslock); }

  • 預定邏輯的是,「SomeClass的」類的多個對象創建新線程並作爲參數傳遞本身的對象,然後調用函數:「someFunc」:

    int SomeClass::startNewThread() 
    { 
    
    pthread_attr_t attr; 
    pthread_t pThreadID; 
    
    if(pthread_attr_init(&attr) != 0) 
        return -1; 
    
    if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) 
        return -2; 
    
    if(pthread_create(&pThreadID, &attr, proxyThreadFunc, this) != 0) 
        return -3; 
    
    if(pthread_attr_destroy(&attr) != 0) 
        return -4; 
    
    return 0; 
    } 
    
    void* proxyThreadFunc(void* someClassObjPtr) 
    { 
    return static_cast<SomeClass*> (someClassObjPtr)->somefunc("long string","long string"); 
    } 
    

    對不起,很長的描述。但我希望問題和預期目的是明確的,如果不讓我知道,我會詳細說明。

    此致敬禮。 Chris

    回答

    1

    1 a/b:不,不會發生。函數的參數及其返回值位於堆棧上,每個線程都有自己的堆棧。然而,其他事情肯定會出錯:

    • 其中一個字符串操作可能會引發異常,從而阻止某個類的鎖被解鎖,並且您的應用程序將掛起。
    • 假設傳遞給函數的字符串是在線程之間共享的(如果它們不是,鎖是不必要的),另一個線程可以在函數被調用之後並且在獲取鎖之前調用它們上的析構函數。在這種情況下,字符串操作會導致未定義的行爲。

    我建議您爲每個線程創建一個新的SomeClass對象。在這種情況下,這些對象的所有成員只能由一個線程訪問,並且不需要受鎖保護。 缺點是在啓動新線程後,您不能從主線程訪問它們。如果需要這樣做,那麼你必須用鎖來保護它們(鎖也是該類的成員)。

    話雖如此,函數somefunc似乎並不影響對象的任何成員,因此不需要保護。考慮線程之間共享的粒度,在我看來,保護鎖應該在調用somefunc的函數中。

    +0

    謝謝你們兩位抽出時間回覆。 – ChrisCphDK 2010-06-11 08:05:01

    0

    一般建議:儘量減少訪問共享數據的地方。通過共享數據,我的意思是任何線程可以在任何時間訪問的數據。

    有接近多線程編程的一些基本方法:

    Producer consumer

    Reader writers

    當然還有其他的方法,但是這兩個是最常用的 - 至少由我(尤其是第一個)。