簡體   English   中英

如何使用C ++和Pthreads安全地對線程中的參數進行操作?

[英]How to safely operate on parameters in threads, using C++ & Pthreads?

我在使用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. 假設動態字符串存儲在堆中,但在運行時在堆棧上分配了對該字符串的引用,這是否正確?

堆棧:[Some mem addr]指向字符串在堆上的位置的指針地址

堆:[Some mem addr]為初始字符串分配的內存可能會增加或縮小

為了使函數線程安全,請使用以下互斥鎖(在“ 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;
}
  1. 這是鎖定在字符串(全部三個)上進行的操作的安全方法,還是在以下情況下調度程序可以停止線程,我認為這會弄亂預期的邏輯:

    一種。 在調用該函數之后,並在該函數在堆棧上的兩個引用指針中設置了參數strOne和strTwo,調度程序占用了線程的處理時間,並允許一個新線程進入,該線程覆蓋了引用指向函數的指針,然后該指針又被調度程序停止,讓第一個線程返回?

    “結果”字符串會發生同樣的情況:第一個字符串生成結果,解鎖互斥鎖,但是在返回調度程序之前,讓另一個線程執行所有工作,覆蓋結果等。

還是在另一個線程執行任務時將參考參數/結果字符串壓入堆棧?

  1. 是在線程中執行此操作並“返回”結果的安全/正確方法,以將引用傳遞給將由結果填充的字符串:

    無效SomeClass :: somefunc(const std :: string&strOne,const std :: string&strTwo,std :: string result){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");
}

很抱歉,冗長的描述。 但我希望問題和意圖明確,如果不能讓我知道,我會詳細說明。

最好的祝福。 克里斯

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

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

我建議您為每個線程創建一個新的SomeClass對象。 在那種情況下,這些對象的所有成員只能由一個線程訪問,而不必由鎖保護。 缺點是,啟動新線程后,您將無法再從主線程訪問它們。 如果那是必需的,那么您必須使用鎖來保護它們(該鎖也將是該類的成員)。

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

一般建議:盡量減少訪問共享數據的位置。 共享數據是指可以隨時通過任何線程訪問的數據。

有幾種通用的方法可以進行多線程編程:

生產者消費者

讀者作家

當然還有其他方式,但是這兩種方式是最常用的-至少對於我來說(尤其是第一種)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM