C++11多線程:並發編程、異步任務、原子操作、鎖機制和線程池

C++11引入了許多新的特性,其中包括對多線程編程的支持。本文將介紹C++11中多線程編程的各種方面,包括並發編程、異步任務、原子操作、鎖機制以及線程池等。

一、並發編程

並發編程是指在一個應用程序中同時執行多個任務的能力。多線程是實現並發編程的一種常見方式。C++11為多線程編程提供了一組重要的工具,包括線程、互斥鎖、條件變量、原子操作和同步隊列。下面分別介紹這些內容。

1. 線程

線程是指進程中執行的並發任務。C++11中的線程類是std::thread,使用它可以創建和控制線程。下面是一個簡單的線程示例,展示了如何創建和啟動一個新的線程。

#include 
#include 

void thread_function()
{
   std::cout << "thread function running" << std::endl;
}

int main()
{
   std::thread t(&thread_function);
   std::cout << "main thread running" << std::endl;
   t.join();
   return 0;
}

在上面的示例中,std::thread對象t是一個新線程,它的構造函數接受線程函數和函數參數。在這個示例中,線程函數是thread_function(),沒有參數。線程對象t被創建後,可以調用它的join()方法來等待線程完成。

2. 互斥鎖和條件變量

在多線程程序中,對共享數據的並發訪問可能會導致問題。為了避免這些問題,C++11提供了互斥鎖和條件變量。互斥鎖可以用於同步多個線程之間的訪問,條件變量可以用於在線程之間傳遞信號。下面是使用互斥鎖和條件變量的示例:

#include 
#include 
#include 
#include 
#include 

std::mutex mtx;
std::condition_variable cv;
std::queue q;
bool ready = false;

void producer_thread()
{
   for (int i = 0; i < 5; ++i) {
      std::unique_lock lock(mtx);
      q.push(i);
      std::cout << "producer thread pushed " << i << std::endl;
      ready = true;
      cv.notify_one();
   }
}

void consumer_thread()
{
   while (true) {
      std::unique_lock lock(mtx);
      while (!ready) cv.wait(lock);
      if (q.empty()) break;
      int data = q.front();
      q.pop();
      std::cout << "consumer thread got " << data << std::endl;
      ready = false;
   }
}

int main()
{
   std::thread producer(producer_thread);
   std::thread consumer(consumer_thread);
   producer.join();
   consumer.join();
   return 0;
}

在上面的示例中,我們使用了互斥鎖和條件變量來同步生產者和消費者線程。生產者線程調用cv.notify_one()來通知消費者線程可以取數據了,消費者線程使用cv.wait(lock)來等待生產者線程的通知。

二、異步任務

異步任務是指程序中可以單獨執行、不阻塞主線程的任務。C++11為異步任務提供了一個很方便的方式:std::async()。使用std::async()可以在新的線程中異步執行一個函數,同時返回一個std::future對象,該對象可以用於獲取函數的返回值或者等待函數執行完成。下面是std::async()的一個示例:

#include 
#include 

int async_function()
{
   std::cout << "async_function running" << std::endl;
   return 42;
}

int main()
{
   std::future f = std::async(std::launch::async, &async_function);
   std::cout << "main thread running" << std::endl;
   std::cout << "async_function returned " << f.get() << std::endl;
   return 0;
}

在上面的示例中,std::async()函數被用來異步執行函數async_function()。該函數返回一個std::future對象f,用於獲取異步函數的返回值。在主函數中,我們使用f.get()方法來等待異步函數執行完成並且獲取其返回值。

三、原子操作和鎖機制

原子操作是指可以在沒有鎖的情況下對共享數據進行讀寫操作的語句。C++11中提供了std::atomic類來支持原子操作。std::atomic類可以確保任何對原子對象的操作都是對整個值進行原子化的,因此不會發生競爭條件。下面是一個原子操作的示例:

#include 
#include 
#include 

std::atomic counter(0);

void thread_function()
{
   for (int i = 0; i < 10000; ++i) {
      counter++;
   }
}

int main()
{
   std::thread t1(thread_function);
   std::thread t2(thread_function);
   t1.join();
   t2.join();
   std::cout << "counter = " << counter << std::endl;
   return 0;
}

上面的示例中,我們使用std::atomic來定義了一個原子化的計數器。在兩個線程中分別對其進行了10000次自增操作。由於使用了std::atomic,所以兩個線程對計數器的自增操作是原子化的,不會導致數據競爭。最終輸出的counter的值為20000。

鎖機制也是避免多線程訪問共享數據時出現數據競爭的一種重要手段。C++11提供了多種類型的鎖來支持多線程程序。下面是使用std::mutex進行線程同步的示例:

#include 
#include 
#include 

std::mutex mtx;
int counter = 0;

void thread_function()
{
   for (int i = 0; i < 10000; ++i) {
      std::unique_lock lock(mtx);
      counter++;
   }
}

int main()
{
   std::thread t1(thread_function);
   std::thread t2(thread_function);
   t1.join();
   t2.join();
   std::cout << "counter = " << counter << std::endl;
   return 0;
}

在上面的示例中,我們使用std::mutex來定義了一個互斥鎖。在兩個線程中對計數器進行自增前,先進行了加鎖操作,以保證操作的原子性和線程安全。最終計數器的值也是20000。

四、線程池

線程池是一種常見的並發編程技術,通過維護一組線程,以待執行的任務隊列作為輸入,執行任務隊列中的任務,以實現多線程並發執行。C++11中並沒有提供線程池的實現,但我們可以自己實現一個簡單的線程池。下面是一個線程池的示例:

#include 
#include 
#include 
#include 
#include 

class ThreadPool
{
public:
   ThreadPool(std::size_t n) : stopped(false)
   {
      for (std::size_t i = 0; i < n; ++i) {
         workers.emplace_back(
            [this] {
               for (;;) {
                  std::function task;
                  {
                     std::unique_lock lock(queue_mutex);
                     condition.wait(lock, [this]() { return stopped || !tasks.empty(); });
                     if (stopped && tasks.empty()) return;
                     task = std::move(tasks.front());
                     tasks.pop();
                  }
                  task();
               }
            }
         );
      }
   }

   template 
   auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of::type>
   {
      using return_type = typename std::result_of::type;

      auto task = std::make_shared<std::packaged_task>(std::bind(std::forward(f), std::forward(args)...));

      std::future res = task->get_future();
      {
         std::unique_lock lock(queue_mutex);
         if (stopped) throw std::runtime_error("enqueue on stopped ThreadPool");
         tasks.emplace([task]() { (*task)(); });
      }
      condition.notify_one();
      return res;
   }

   ~ThreadPool()
   {
      {
         std::unique_lock lock(queue_mutex);
         stopped = true;
      }
      condition.notify_all();
      for (std::thread& worker : workers)
         worker.join();
   }

private:
   std::vector workers;
   std::queue<std::function> tasks;
   std::mutex queue_mutex;
   std::condition_variable condition;
   bool stopped;
};

int main()
{
   ThreadPool pool(4);
   std::vector<std::future> results;

   for (int i = 0; i  int {
            std::cout << "task " << i << " running" << std::endl;
            return i * i;
         }, i)
      );
   }

   for (std::future& result : results) {
      std::cout << "result = " << result.get() << std::endl;
   }

   return 0;
}

在上面的示例中,我們定義了一個ThreadPool類,它維護了一組線程和一個任務隊列。線程每次從任務隊列中取出一個任務執行,直到任務隊列為空或者被告知停止。ThreadPool類提供了enqueue()函數來向任務隊列中添加任務,enqueue()函數返回一個std::future對象,用於獲取任務的返回值。

結論

本文介紹了C++11中多線程編程的各種方面,包括並發編程、異步任務、原子操作、鎖機制以及線程池等。多線程編程是一項複雜的任務,需要仔細考慮應用程序的數據共享和線程同步問題。通過了解C++11多線程編程提供的工具和技術,可以使多線程編程更加容易和高效。

原創文章,作者:DISNI,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/329672.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
DISNI的頭像DISNI
上一篇 2025-01-14 18:55
下一篇 2025-01-14 18:55

相關推薦

  • Python多線程讀取數據

    本文將詳細介紹多線程讀取數據在Python中的實現方法以及相關知識點。 一、線程和多線程 線程是操作系統調度的最小單位。單線程程序只有一個線程,按照程序從上到下的順序逐行執行。而多…

    編程 2025-04-29
  • Python線程等待指南

    本文將從多個方面詳細講解Python線程等待的相關知識。 一、等待線程結束 在多線程編程中,經常需要等待線程執行完畢再進行下一步操作。可以使用join()方法實現等待線程執行完畢再…

    編程 2025-04-29
  • Python兩個線程交替打印1到100

    這篇文章的主題是關於Python多線程的應用。我們將會通過實際的代碼,學習如何使用Python兩個線程交替打印1到100。 一、創建線程 在Python中,我們可以使用Thread…

    編程 2025-04-28
  • ROS線程發佈消息異常解決方法

    針對ROS線程發佈消息異常問題,我們可以從以下幾個方面進行分析和解決。 一、檢查ROS代碼是否正確 首先,我們需要檢查ROS代碼是否正確。可能會出現的問題包括: 是否正確初始化RO…

    編程 2025-04-28
  • Spring S_CSRF防護機制實現及應用

    Spring S_CSRF防護機制是Spring Security框架提供的一個針對跨站請求偽造攻擊(CSRF)的保護機制。本文將從以下幾個方面詳細介紹Spring S_CSRF防…

    編程 2025-04-28
  • Python線程池並發爬蟲

    Python線程池並發爬蟲是實現多線程爬取數據的常用技術之一,可以在一定程度上提高爬取效率和數據處理能力。本文將從多個方面對Python線程池並發爬蟲做詳細的闡述,包括線程池的實現…

    編程 2025-04-27
  • 多線程和多進程的應用

    多線程和多進程是現代編程中常用的技術,可以提高程序的效率和性能。本文將從不同的角度對多線程和多進程進行詳細的介紹和應用。 一、多線程 vs 多進程 多線程和多進程都是為了實現程序並…

    編程 2025-04-27
  • Python的垃圾回收機制

    本文將對Python的垃圾回收機制進行詳細闡述,着重介紹它的基本原理和實現方式。此外,我們還將介紹常見的問題及解決方法,並給出相應的代碼示例。 一、Python的垃圾回收概述 垃圾…

    編程 2025-04-27
  • Python多線程模塊實踐

    本文將向大家介紹Python中的多線程模塊,並通過示例代碼來展示如何靈活使用線程提升程序的性能。同時,本文還將討論Python多線程模塊使用中可能遇到的一些問題及其解決方法。 一、…

    編程 2025-04-27
  • 線程池中的一個線程異常了會被怎麼處理

    本文將從以下幾個方面對線程池中的一個線程異常了會被怎麼處理進行詳細闡述:異常的類型、如何捕獲異常、異常的處理方式。 一、異常的類型 在線程池中,可以出現多種類型的異常,例如線程執行…

    編程 2025-04-27

發表回復

登錄後才能評論