2012-05-12 121 views
1

我寫日誌信息的功能。 我將從不同的線程調用此打印功能。 我的代碼如下:C++成員函數線程安全

MyLog::printLog(const char* s) 
    { 

      std::string myline(s); 
      //m_Mutex is class member and there will be only object for this class 
      // shared by all threads 
      int ret = pthread_mutex_lock(&m_Mutex); 
      if (ret != 0) 
      { 
        std::cout<<" trying to lock same mutex char* "<<std::endl; 

      } 


      //code to log message in File 

      pthread_mutex_unlock(&m_Mutex); 
    } 

我的問題是,如果上述功能從不同的線程調用參數,如「從線程1」,「從線程2」,......會不會有任何機會爲const char * s會混亂打印錯誤的值。? 我希望我的問題很清楚。

回答

1

如果您從不同線程調用此函數,並且您對參數const char* s所做的任何更改都受您的互斥鎖m_Mutex保護,那麼您將會很好,不會有任何混亂。

編輯

事實上,每次調用此函數將它從不同的線程調用時自己的堆棧,並看到它const char*你不能改變你的說法,所以沒有必要用,以保護它互斥。

您的變量s是它被調用的線程的局部變量,它是const

然後複製到本地變量myline是絕對不會惹什麼,導致每個線程有它的調用堆棧,在其居住的myline實例時調用此函數,這是完全獨立的,並獨立於任何其他的線。

+0

其實,我的疑問是,當打印日誌被稱爲thred1,爲const char * S仍將指向堆棧變量是perfectlly確定。但是當第二個線程調用它並將它存儲到第一個線程的局部變量之前,線程2中沒有任何機會'會指向局部變量導致混亂?我希望我有道理 –

+0

我不確定我是否關注你,但傳遞給函數的參數是'const',因此你不能改變它,你必須在做任何改變之前複製它,所以沒有改變的混亂。你將它複製到'std :: string'中,複製數據,所以它們都是本地線程。 –

+0

行..還有另一個函數,我正在實現作爲MyLog :: printLog(char * s)爲:{std :: string myline(s); int ret = pthread_mutex_lock(&m_Mutex); if(ret!= 0){std :: cout <<「試圖鎖定相同的互斥字符*」<< std :: endl; } //在文件中記錄消息的代碼pthread_mutex_unlock(&m_Mutex); }在這種情況下會出現問題嗎?作爲它的char *而不是const char *? –

3

你的功能將工作像您期望的,因爲myline是一個局部變量(每個線程都有自己的堆棧,因此將有自己的myline實例)

+0

非常感謝這麼快的迴應; –

+0

雖然這個答案是正確的,但推理是錯誤的。這是安全的,因爲與每個線程都有自己的堆棧無關。例如,即使多個myline實例將在同一個堆棧上創建,遞歸調用該函數的單個線程也同樣安全。重點是每次調用此函數都會創建自己的「myline」實例。它與創建這些實例的位置無關。 –

+0

我的意思是每個局部變量都不相同(它有不同的內存位置),對於遞歸函數(本地位於同一線程堆棧中的堆棧調用幀內部)或不同線程(本地位於不同的堆棧內) 。並且遞歸函數沒有同步問題(每個線程中只有一個調用幀處於活動狀態)。 –

1

這取決於你如何調用printLog功能。如果地址傳遞給函數得到由不同的線程突變的字符串,那麼你可能看不到它的日誌功能內部的一致視圖。如果你傳遞一個指向不可變字符串的指針,例如文字,那麼你很好。

這裏是一個很好的例子:

void from_thread_one() 
{ 
    MyLog::printLog("Hello World"); // immutable string 
} 

void from_thread_two() 
{ 
    MyLog::printLog("Another text"); // ditto 
} 

在另一方面,這裏是那也不行,有一個比賽的例子:

char globalString[] = "This is a really long string"; 

void from_thread_one() 
{ 
    globalString[5] = 'A'; 
    MyLog::printLog(globalString); 
} 

void from_thread_two() 
{ 
    globalString[8] = 'Q'; 
    MyLog::printLog(globalString); 
} 

在這種背景下,要製作一個副本串(通過std::string myline(s);)而陣列中的內容指向s可以同時在其它線程被改變。在這種情況下,取消引用char指針也必須在臨界區內發生。

您的設置最根本的問題是,原始字符指針具有告訴其行爲是可以接受的,這是不是用戶沒有隱含的語義。假如你在實際std::string按值傳遞,你會刪除有關從printLog功能同步訪問字符串的不確定性和完全搬到責任到調用。

+0

明白了你的觀點。我不會像第二種方式那樣稱呼它。我正在使用第一種方式。所以它的線程安全。 –