Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Analisis isu konkurensi dalam pengaturcaraan berbilang benang C++

Analisis isu konkurensi dalam pengaturcaraan berbilang benang C++

王林
王林asal
2023-10-08 11:05:061241semak imbas

Analisis isu konkurensi dalam pengaturcaraan berbilang benang C++

Analisis isu konkurensi dalam pengaturcaraan berbilang benang C++

Dengan pembangunan berterusan perkakasan komputer, pemproses berbilang teras telah menjadi arus perdana. Dalam kes ini, menggunakan multi-threading untuk menggunakan sepenuhnya prestasi pemproses berbilang teras telah menjadi teknologi penting dalam pembangunan program. Walau bagaimanapun, dalam pengaturcaraan berbilang benang, disebabkan oleh operasi serentak antara berbilang benang, beberapa masalah sering berlaku. Artikel ini akan menggunakan contoh kod khusus untuk menganalisis isu konkurensi dalam pengaturcaraan berbilang benang C++.

  1. Persaingan untuk berkongsi sumber antara rangkaian

Apabila berbilang rangkaian mengakses dan mengubah suai sumber dikongsi pada masa yang sama, mudah menyebabkan persaingan data. Keputusan perlumbaan data tidak dapat diramalkan dan boleh menyebabkan ralat program. Berikut ialah kod sampel mudah:

#include <iostream>
#include <thread>

int count = 0;

void increment()
{
    for (int i = 0; i < 100000; ++i)
    {
        count++;
    }
}

int main()
{
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "count: " << count << std::endl;

    return 0;
}

Dalam kod di atas, dua utas secara serentak menambah kiraan. Memandangkan dua utas mengakses dan mengubah suai kiraan pada masa yang sama, persaingan data mungkin berlaku. Hasil daripada menjalankan kod di atas tidak ditentukan dan mungkin berbeza setiap kali ia dijalankan.

Penyelesaian kepada masalah ini adalah dengan memperkenalkan kunci mutex atau operasi atom. Tingkatkan kod di atas:

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

int count = 0;
std::mutex mtx;

void increment()
{
    for (int i = 0; i < 100000; ++i)
    {
        std::lock_guard<std::mutex> lock(mtx);
        count++;
    }
}

int main()
{
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "count: " << count << std::endl;

    return 0;
}

Dalam kod yang dipertingkatkan, kunci mutex mtx diperkenalkan melalui std::lock_guard<:mutex></:mutex> Kunci dan buka kunci mutex secara automatik . Dengan cara ini, apabila mengubah suai count dalam fungsi increment, ia akan dikunci terlebih dahulu untuk memastikan hanya satu utas boleh mengakses dan mengubah suai sumber yang dikongsi pada masa yang sama. Menjalankan kod yang dipertingkatkan memberikan hasil yang betul. mtx,通过std::lock_guard<:mutex></:mutex>来对互斥锁进行自动加锁和解锁。这样,在increment函数中对count进行修改时,会先加锁,保证同一时间只有一个线程能够访问和修改共享资源。运行改进后的代码,可以得到正确的结果。

  1. 死锁

另一个常见的并发问题是死锁。死锁是指两个或多个线程相互等待对方释放锁而无法继续执行的情况。以下是一个简单的死锁示例代码:

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

std::mutex mtx1, mtx2;

void thread1()
{
    std::lock_guard<std::mutex> lock1(mtx1);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::lock_guard<std::mutex> lock2(mtx2);

    std::cout << "Thread 1" << std::endl;
}

void thread2()
{
    std::lock_guard<std::mutex> lock2(mtx2);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::lock_guard<std::mutex> lock1(mtx1);

    std::cout << "Thread 2" << std::endl;
}

int main()
{
    std::thread t1(thread1);
    std::thread t2(thread2);

    t1.join();
    t2.join();

    return 0;
}

上述代码中,thread1thread2两个线程分别对mtx1mtx2进行加锁。但是在加锁后,它们又试图对另一个锁进行加锁,从而形成了相互等待的死锁情况。这将导致程序无法继续执行。

解决死锁问题的方法是对锁的获取顺序进行统一。即,所有线程在获取锁的时候,都按照相同的顺序获取锁。修改上述代码:

void thread1()
{
    std::lock_guard<std::mutex> lock1(mtx1);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::lock_guard<std::mutex> lock2(mtx2);

    std::cout << "Thread 1" << std::endl;
}

void thread2()
{
    std::lock_guard<std::mutex> lock1(mtx1);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::lock_guard<std::mutex> lock2(mtx2);

    std::cout << "Thread 2" << std::endl;
}

在改进后的代码中,对锁的获取顺序进行了统一,都是先获取mtx1,再获取mtx2

    Kebuntuan

    Satu lagi masalah konkurensi biasa ialah kebuntuan. Kebuntuan ialah situasi di mana dua atau lebih utas tidak dapat meneruskan pelaksanaan sementara menunggu satu sama lain melepaskan kunci. Berikut ialah kod contoh kebuntuan mudah:

    rrreee🎜Dalam kod di atas, dua utas thread1 dan thread2 bertanggungjawab untuk mtx1 dan mtx2 melakukan penguncian. Tetapi selepas mengunci, mereka cuba mengunci kunci lain, mengakibatkan keadaan buntu menunggu antara satu sama lain. Ini akan menghalang program daripada diteruskan. 🎜🎜Cara untuk menyelesaikan masalah kebuntuan adalah dengan menyatukan susunan perolehan kunci. Iaitu, semua benang memperoleh kunci dalam susunan yang sama apabila memperoleh kunci. Ubah suai kod di atas: 🎜rrreee🎜Dalam kod yang dipertingkatkan, susunan pemerolehan kunci disatukan mtx1 diperoleh dahulu, dan kemudian mtx2 diperoleh. Dengan cara ini, berlakunya kebuntuan dapat dielakkan. 🎜🎜Ringkasan: 🎜🎜Isu konkurensi dalam pengaturcaraan berbilang benang adalah salah satu masalah biasa dalam pembangunan program. Artikel ini memperkenalkan secara ringkas persaingan sumber kongsi dan masalah kebuntuan dalam masalah konkurensi melalui contoh kod tertentu dan menyediakan penyelesaian yang sepadan. Dalam pengaturcaraan sebenar, kita perlu mempunyai pemahaman yang lebih mendalam tentang prinsip dan teknik pengaturcaraan berbilang benang untuk mengelakkan masalah konkurensi dan memastikan ketepatan dan kestabilan operasi program. 🎜

Atas ialah kandungan terperinci Analisis isu konkurensi dalam pengaturcaraan berbilang benang C++. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
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