使用C++在Linux中創建線程

一、使用 pthread_create 函數創建線程

pthread_create 是Linux下常見的創建線程的方法,它包含在 pthread 庫中。通過它我們可以在一個程序中創建多個線程來並行處理任務。

下面是一個簡單的示例,通過 pthread_create 創建兩個線程:

#include <iostream>
#include <pthread.h>

using namespace std;

void* threadFunc(void* arg)
{
    int num = *((int*) arg);
    cout << "Thread #" << num << ": hello world!" << endl;
    return NULL;
}

int main(int argc, char** argv)
{
    pthread_t thread1, thread2;
    int thread1Num = 1, thread2Num = 2;

    pthread_create(&thread1, NULL, threadFunc, &thread1Num);
    pthread_create(&thread2, NULL, threadFunc, &thread2Num);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    cout << "Main thread exiting" << endl;
    return 0;
}

在上面的代碼中,我們通過調用 pthread_create 函數來創建兩個線程 thread1 和 thread2。每個線程都調用 threadFunc 函數,在這個函數里我們輸出了一個簡單的 “hello world”。最後,我們通過調用 pthread_join 函數來等待兩個線程的結束,然後程序才能正常退出。

二、使用 std::thread 類創建線程

C++11 標準引入了 std::thread 類,可以方便地創建線程。相比於 pthread_create 函數,std::thread 更具有面向對象的特徵,更加易於使用。

下面是一個使用 std::thread 創建線程的示例:

#include <iostream>
#include <thread>

using namespace std;

void threadFunc(int num)
{
    cout << "Thread #" << num << ": hello world!" << endl;
}

int main(int argc, char** argv)
{
    thread thread1(threadFunc, 1);
    thread thread2(threadFunc, 2);

    thread1.join();
    thread2.join();

    cout << "Main thread exiting" << endl;
    return 0;
}

在上面的代碼中,我們通過使用 std::thread 類創建了兩個線程 thread1 和 thread2。和 pthread_create 不同的是,我們使用了類的構造函數來創建線程,也就是說,每個線程都是一個對象。在構造線程的時候,我們將要執行的函數和它的參數作為參數傳入線程構造函數。和 pthread_create 一樣,我們也需要調用 join() 函數等待線程結束。

三、線程同步與互斥

在多線程程序中,通常都需要處理線程同步和互斥的問題。如果多個線程同時訪問同一個數據,可能會導致數據出錯或者延時。因此,我們需要使用鎖來控制對共享資源的訪問,避免多個線程同時訪問同一個數據。

下面是一個使用 pthreads 庫來保護臨界段的示例:

#include <iostream>
#include <pthread.h>

using namespace std;

int count = 0;
pthread_mutex_t count_mutex;

void* threadFunc(void* arg)
{
    for (int i = 0; i < 5; i++) {
        pthread_mutex_lock(&count_mutex);
        count++;
        cout << "Thread #" << *((int*) arg) << " count = " << count << endl;
        pthread_mutex_unlock(&count_mutex);
    }
    return NULL;
}

int main(int argc, char** argv)
{
    pthread_t thread1, thread2;
    int thread1Num = 1, thread2Num = 2;

    pthread_mutex_init(&count_mutex, NULL);

    pthread_create(&thread1, NULL, threadFunc, &thread1Num);
    pthread_create(&thread2, NULL, threadFunc, &thread2Num);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    pthread_mutex_destroy(&count_mutex);

    cout << "Main thread exiting" << endl;
    return 0;
}

在上面的示例中,我們使用了 pthreads 庫的互斥量來保護全局變數 count。在 threadFunc 函數中,我們使用 pthread_mutex_lock 和 pthread_mutex_unlock 函數來加鎖和解鎖。這樣,當兩個線程同時訪問 count 變數時,一次只能有一個線程進行訪問,避免了數據錯亂。

除了使用互斥量外,C++11 中也提供了 std::mutex 來進行鎖操作。std::mutex 的用法和 pthread_mutex_t 是類似的,使用起來更加方便。

四、線程池

線程池是一種常見的多線程編程技術,通常用於處理大量並發請求。線程池中創建好多個線程,等待隊列中的任務。當任務來臨時,線程池中的線程會從隊列中取出任務進行處理,完成後再次回到隊列中等待新的任務。

下面是一個簡單的線程池實現:

#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>

using namespace std;

class ThreadPool {
public:
    ThreadPool(int numThreads) {
        for (int i = 0; i < numThreads; i++) {
            threads.emplace_back([this] {
                for (;;) {
                    function<void()> task;
                    {
                        unique_lock<mutex> lock(this->queueMutex);
                        this->condition.wait(lock, [this] {
                            return !this->tasks.empty() || this->stop;
                        });
                        if (this->stop && this->tasks.empty()) {
                            return;
                        }
                        task = std::move(this->tasks.front());
                        this->tasks.pop();
                    }
                    task();
                }
            });
        }
    }

    ~ThreadPool() {
        {
            unique_lock<mutex> lock(queueMutex);
            stop = true;
        }
        condition.notify_all();
        for (auto &thread : threads) {
            thread.join();
        }
    }

    template <class Func, class... Args>
    auto enqueue(Func&& func, Args&&... args) -> future<typename result_of<Func(Args...)>::type> {
        using return_type = typename result_of<Func(Args...)>::type;
        auto task = make_shared<packaged_task<return_type()>>(
            bind(forward<Func>(func), forward<Args>(args)...)
        );
        future<return_type> res = task->get_future();
        {
            unique_lock<mutex> lock(queueMutex);
            tasks.emplace([task]() { (*task)(); });
        }
        condition.notify_one();
        return res;
    }

private:
    vector<thread> threads;
    queue<function<void()>> tasks;
    mutex queueMutex;
    condition_variable condition;
    bool stop = false;
};

void threadFunc(int num)
{
    cout << "Thread #" << num << " hello world!" << endl;
}

int main(int argc, char** argv)
{
    ThreadPool pool(4);

    pool.enqueue(threadFunc, 1);
    pool.enqueue(threadFunc, 2);
    pool.enqueue(threadFunc, 3);
    pool.enqueue(threadFunc, 4);

    return 0;
}

在上面的示例中,我們實現了一個簡單的線程池。它包含了一個線程池的類 ThreadPool。它使用 std::vector 存儲所有線程,std::queue 存儲所有任務,std::mutex和 std::condition_variable 用於線程同步。

線程池的構造函數需要輸入線程數量 numThreads 作為參數,它會在構造函數中創建 numThreads 個線程。enqueue 函數可以添加新任務到隊列中,添加的任務將會在隊列中等待線程池中的線程去執行。

在 main 函數中,我們創建了一個線程池 pool,並且通過 pool.enqueue 函數添加了 4 個任務,並由線程池執行。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/240097.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 12:19
下一篇 2024-12-12 12:19

相關推薦

  • 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
  • Python線程池並發爬蟲

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

    編程 2025-04-27
  • 如何在Linux中添加用戶並修改配置文件

    本文將從多個方面詳細介紹在Linux系統下如何添加新用戶並修改配置文件 一、添加新用戶 在Linux系統下創建新用戶非常簡單,只需使用adduser命令即可。使用以下命令添加新用戶…

    編程 2025-04-27
  • 如何解決linux jar包 invalid or corrupt jarfile問題

    對於許多開發人員和系統管理員在Linux環境下使用Java開發過程中遇到的一個常見的問題是 invalid or corrupt jarfile(無效或損壞的jar文件)錯誤。當您…

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

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

    編程 2025-04-27
  • 在Linux上安裝JRE並配置環境變數

    本文將從以下幾個方面為您詳細闡述如何在Linux系統上,通過自己賬戶安裝JRE,並且配置環境變數。 一、安裝JRE 在進行安裝前,我們需要下載JRE的安裝包並解壓,可以從官方網站下…

    編程 2025-04-27
  • GTKAM:Linux下的照片管理器

    GTKAM是用於Linux操作系統的一款照片管理器,它支持多種相機及存儲設備,並提供了一系列強大的工具,讓用戶可以方便地瀏覽、管理、編輯和導出照片。本文將從多個方面對GTKAM進行…

    編程 2025-04-27
  • Linux sync詳解

    一、sync概述 sync是Linux中一個非常重要的命令,它可以將文件系統緩存中的內容,強制寫入磁碟中。在執行sync之前,所有的文件系統更新將不會立即寫入磁碟,而是先緩存在內存…

    編程 2025-04-25

發表回復

登錄後才能評論