簡體   English   中英

這個代碼是線程安全的嗎?

[英]ls this code thread-safe?

我正在重構一些耗時的函數,以便可以從線程中調用它,但是我無法解決這個問題(對線程編程不是很熟悉)。

在任何時候,用戶都可以取消,該功能將停止。 我不想在用戶取消后立即殺死該線程,因為它可能導致某些數據完整性問題。 相反,我將在函數的多個位置檢查函數是否已取消,如果已取消,則退出。 我只會在我知道可以安全退出的情況下這樣做。

該函數的整個代碼將在互斥鎖內。 這是我想到的偽代碼:

SomeClass::SomeClass() {
    cancelled_ = false;
}

void SomeClass::cancelBigSearch() {
    cancelled_ = true;
}

void SomeClass::bigSearch() {
    mutex.lock();

    // ...
    // Some code
    // ...

    // Safe to exit at this point
    if (cancelled_) {
        mutex.unlock();
        cancelled_ = false;
        return;
    } 

    // ...
    // Some more code
    // ...

    if (cancelled_) {
        mutex.unlock();
        cancelled_ = false;
        return;
    }   

    // ...
    // Again more code
    // ...

    if (cancelled_) {
        mutex.unlock();
        cancelled_ = false;
        return;
    }   

    mutex.unlock();
}

因此,當用戶開始搜索時,新線程將調用bigSearch() 如果用戶取消, cancelBigSearch()調用cancelBigSearch()並設置cancelled_標志。 然后,當bigSearch()到達可以安全退出的位置時,它將退出。

知道這是否全部是線程安全的嗎?

您應該使用另一個互斥鎖來鎖定對cancelled_訪問,因此檢查和設置不會同時發生。 除此之外,我認為您的方法還可以

更新:另外,請確保不能從SomeClass::bigSearch()拋出任何異常,否則互斥體可能會保持鎖定狀態。 為了確保所有返回路徑都可以解鎖互斥鎖,您可能希望用if (!cancelled_)包圍代碼的處理部分,並僅在方法的最后返回(在該方法的最后一個調用unlock()互斥體。

更好的是,將互斥體包裝在RAII( 資源分配是初始化 )的對象中,因此,無論函數如何結束(異常或其他方式),都可以保證互斥體被解鎖。

是的,這是線程安全的。 但:

  1. 處理器可以具有單獨的緩存,並且可以緩存它自己的cancelled_副本,通常互斥鎖同步功能會應用適當的緩存同步。
  2. 編譯器生成的代碼可以對您的數據局部性做出無效的假設,這可能導致無法及時cancelled_ 一些特定於平台的命令可以在這里提供幫助,或者您可以簡單地使用其他機制。

所有這些導致線程沒有按您希望的那樣及時取消。

您的代碼使用模式是簡單的“信號發送”。 因此,您需要將信號傳輸到線程。 信號模式允許多次觸發相同的觸發(信號),並稍后將其清除。

可以使用以下方法進行模擬:

  • 原子操作
  • 互斥鎖保護的變量
  • 信號同步原語

不是線程安全的,因為一個線程可以同時讀取cancelled_ ,而另一個線程向它寫入,這是數據競爭,這是未定義的行為。

正如其他人所建議的那樣,可以將原子類型用於cancelled_或使用另一個互斥體對其進行保護。

您還應該使用RAII類型來鎖定互斥鎖。

例如

void SomeClass::cancelBigSearch() {
  std::lock_guard<std::mutex> lock(cxlMutex_);
  cancelled_ = true;
}

bool SomeClass::cancelled() {
  std::lock_guard<std::mutex> lock(cxlMutex_);
  if (cancelled_) {
    // reset to false, to avoid caller having to lock mutex again to reset it
    cancelled_ = false;
    return true;
  }
  return false;
}

void SomeClass::bigSearch() {
  std::lock_guard<std::mutex> lock(mutex);

  // ...
  // Some code
  // ...

  // Safe to exit at this point
  if (cancelled())
    return;

  // ...
  // Some more code
  // ...

  if (cancelled())
    return;

  // ...
  // Again more code
  // ...

  if (cancelled())
    return;
}

暫無
暫無

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

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