Teknik pengoptimuman multithreading dalam C++

王林
Lepaskan: 2023-08-22 12:53:12
asal
1085 orang telah melayarinya

Teknik pengoptimuman multithreading dalam C++

Dengan perkembangan teknologi komputer dan peningkatan prestasi perkakasan, teknologi multi-threading telah menjadi kemahiran penting untuk pengaturcaraan moden. C++ ialah bahasa pengaturcaraan klasik yang turut menyediakan banyak teknologi multi-threading yang berkuasa. Artikel ini akan memperkenalkan beberapa teknik pengoptimuman berbilang benang dalam C++ untuk membantu pembaca menggunakan teknologi berbilang benang dengan lebih baik.

1. Gunakan std::thread

C++11 memperkenalkan std::thread, yang secara langsung menyepadukan teknologi multi-threading ke dalam perpustakaan standard. Mencipta utas baharu menggunakan std::thread adalah sangat mudah, hanya lulus penunjuk fungsi. Contohnya:

#include <thread>
#include <iostream>

void hello()
{
    std::cout << "Hello World!";
}

int main()
{
    std::thread t(hello);
    t.join();
    return 0;
}
Salin selepas log masuk

Kod di atas mencipta utas t baharu, melaksanakan fungsi helo dan menunggu utas t selesai. Ambil perhatian bahawa penciptaan dan pemusnahan benang memerlukan jumlah overhed tertentu, jadi std::thread perlu digunakan secara rasional.

2. Gunakan std::async

std::async ialah satu lagi teknologi berbilang benang yang mudah digunakan. Gunakan std::async untuk mengurus perlaksanaan tugas tak segerak dan mendapatkan hasil dengan lebih mudah. Contohnya:

#include <future>
#include <iostream>

int add(int a, int b)
{
    return a + b;
}

int main()
{
    auto async_result = std::async(add, 1, 2);
    std::cout << async_result.get();
    return 0;
}
Salin selepas log masuk

Kod di atas memanggil fungsi tambah untuk mengira 1+2 secara tak segerak dan menggunakan objek std::depan untuk mengurus perolehan hasil pengiraan. Perlu diingat bahawa std::async menggunakan strategi std::launch::async secara lalai dan akan melaksanakan fungsi dalam urutan baharu. Jika anda ingin menggunakan strategi std::launch::deferred, anda perlu menentukannya secara manual. Walau bagaimanapun, menggunakan strategi std::launch::deferred akan menyebabkan fungsi dilaksanakan hanya apabila std::future::get() dipanggil, jadi pilihan perlu dibuat berdasarkan kes demi kes.

3. Gunakan std::condition_variable

Dalam pengaturcaraan multi-thread, komunikasi dan penyegerakan perlu dijalankan antara thread, dan std::condition_variable boleh mencapai tujuan ini dengan baik. Menggunakan std::condition_variable membenarkan satu utas menunggu keadaan tertentu bagi utas lain menjadi benar, dengan itu mencapai penyegerakan antara utas. Contohnya:

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

std::mutex mutex;
std::condition_variable cv;
bool ready = false;

void producer()
{
    std::unique_lock<std::mutex> lock(mutex);
    // wait for the condition to become true
    cv.wait(lock, [] { return ready; });
    std::cout << "Producer done." << std::endl;
}

void consumer()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    ready = true;
    std::cout << "Consumer done." << std::endl;
    cv.notify_one();
}

int main()
{
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join();
    t2.join();
    return 0;
}
Salin selepas log masuk

Kod di atas mencipta dua utas t1 dan t2, di mana t1 menunggu sehingga pembolehubah keadaan sedia menjadi benar, manakala t2 menetapkan pembolehubah keadaan kepada benar selepas menunggu selama 1 saat dan memberitahu t1. Perlu diingat bahawa std::condition_variable mesti digunakan bersama dengan std::mutex untuk menghalang berbilang benang daripada mengakses pembolehubah keadaan pada masa yang sama.

4. Gunakan kumpulan benang

Dalam kes sejumlah besar tugasan jangka pendek yang perlu dibuat dan dijalankan, kumpulan benang sering digunakan untuk meningkatkan prestasi program. Kumpulan benang mengekalkan bilangan benang tertentu dan mengurus peruntukan dan pelaksanaan tugas. Menggunakan kumpulan benang boleh mengelakkan overhed tambahan untuk kerap mencipta dan memusnahkan benang, sambil memanfaatkan sepenuhnya CPU berbilang teras. Contohnya:

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

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

    ~ThreadPool()
    {
        {
            std::unique_lock<std::mutex> lock{ mutex };
            stop = true;
        }
        condition.notify_all();
        for (auto& worker : pool)
        {
            worker.join();
        }
    }

    template <typename F, typename... Args>
    auto enqueue(F&& f, Args&&... args)
        -> std::future<typename std::result_of<F(Args...)>::type>
    {
        using return_type = typename std::result_of<F(Args...)>::type;
        auto task = std::make_shared<std::packaged_task<return_type()>>(
            std::bind(std::forward<F>(f), std::forward<Args>(args)...));
        std::future<return_type> future = task->get_future();
        {
            std::unique_lock<std::mutex> lock{ mutex };
            if (stop) throw std::runtime_error("enqueue on stopped ThreadPool");
            tasks.emplace([task](){ (*task)(); });
        }
        condition.notify_one();
        return future;
    }

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

void hello()
{
    std::cout << "Hello World!" << std::endl;
}

int add(int a, int b)
{
    return a + b;
}

int main()
{
    {
        ThreadPool pool;
        auto f1 = pool.enqueue(hello);
        auto f2 = pool.enqueue(add, 1, 2);
        std::cout << f2.get() << std::endl;
    }
    return 0;
}
Salin selepas log masuk

Kod di atas mentakrifkan kelas ThreadPool, yang mengandungi berbilang urutan dan baris gilir tugas. Kumpulan benang terus mengambil tugasan daripada baris gilir tugas dan melaksanakannya sehingga baris gilir kosong atau kumpulan benang berhenti. Gunakan kaedah ThreadPool::enqueue untuk menambah tugasan pada baris gilir tugas dan mengembalikan objek std::depan untuk mengurus hasil pelaksanaan tugas.

Secara umumnya, C++ menyediakan pelbagai teknologi berbilang benang untuk membantu pembangun memanfaatkan prestasi CPU berbilang teras dan mengurus urutan serta tugasan dengan lebih fleksibel. Pembangun harus menggunakan teknik ini dengan sewajarnya untuk mengoptimumkan prestasi program.

Atas ialah kandungan terperinci Teknik pengoptimuman multithreading dalam C++. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!