天天看點

C++&&QT基礎多線程總結

C++&&QT基礎多線程總結

轉自

https://blog.csdn.net/czyt1988/article/details/64441443/            //好的學習文章

如果你的代碼所在的程序中有多個線程在同時運作,而這些線程可能會同時運作這段代碼。如果每次運作結果和單線程運作的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。

好比你有兩個一模一樣的銀行卡(賬戶一樣,餘額一樣,當然現實中是沒有的),假如卡上餘額1000塊,而你跟你女朋友同時在不同的ATM上面取1000塊錢(是同時哦,理想中的同時),如果線程不安全,那麼倆人都能同時取出1000塊(賺死了)。而如果線程安全的話,隻能一個人同時操作一個賬戶,當這個賬戶正在被操作時,是被鎖起來的,不給别人動的,隻能你自己動,你動完了别人才能動。

3.為什麼會有線程安全問題?

線程安全問題都是由全局變量及靜态變量引起的。

若每個線程中對全局變量、靜态變量隻有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程同時執行寫操作,一般都需要考慮線程同步,否則的話就可能影響線程安全。

安全性:

比如一個 ArrayList 類,在添加一個元素的時候,它可能會有兩步來完成:1. 在 Items[Size] 的位置存放此元素;2. 增大 Size 的值。

在單線程運作的情況下,如果 Size = 0,添加一個元素後,此元素在位置 0,而且 Size=1;

而如果是在多線程情況下,比如有兩個線程,線程 A 先将元素存放在位置 0。但是此時 CPU 排程線程A暫停,線程 B 得到運作的機會。線程B也向此 ArrayList 添加元素,因為此時 Size 仍然等于 0 (注意哦,我們假設的是添加一個元素是要兩個步驟哦,而線程A僅僅完成了步驟1),是以線程B也将元素存放在位置0。然後線程A和線程B都繼續運作,都增加 Size 的值。

那好,我們來看看 ArrayList 的情況,元素實際上隻有一個,存放在位置 0,而 Size 卻等于 2。這就是“線程不安全”了

QProcess :程序

QThread:線程

QT中建立線程 一般子類化QThread 然後重寫run函數

thread.start() 開始一個線程 預設調用run函數

thread.stop中止一個線程

繼承自QThread的子類 thread中的函數 隻有run這個函數的内容是在建立出來的新的線程裡 其他函數還是在原來的線程裡。

通過上面的測試,我們在使用線程的時候,就可以将一個類派生自QObject,然後實作所有的signal/slot,然後通過調用movetothread函數來使他們執行在新的線程裡面,而不是每次都要重新派生QThread,并且派生QThread函數的另外一個不好的地方是隻有run函數内部的代碼才會執行在新線程裡面,相比起來,派生QObject并使用movetothread函數更具有靈活性。

标準多線程生産者和消費者的示例

std::list<std::string>       packet_str_vec; //解完包後的string_vec

std::mutex                      m_mutex;        //鎖    

std::condition_variable   m_cvItems;      //條件變量

生産者:

void Net::NetTastHandle::AddPacketVec(std::string packet_str)

{

    std::unique_lock<std::mutex> guard(m_mutex);//上鎖

       packet_str_vec.push_back(packet_str);

       m_cvItems.notify_all();

}

消費者:

void NetTastHandle::Run()

{

    while (!stop_flag)

    {

        std::unique_lock<std::mutex> guard(m_mutex);//上鎖(保護條件變量和list組)

        while (packet_str_vec.empty())              //防止線程虛假喚醒

        {

            //如果獲得了互斥鎖,但是條件不合适的話,pthread_cond_wait會釋放鎖,不往下執行。

            //當發生變化後,條件合适,pthread_cond_wait将直接獲得鎖。

            m_cvItems.wait(guard);                  //條件變量

        }

        string cur_str = packet_str_vec.front();  

        packet_str_vec.pop_front();               //删除棧首

        //進一步解包。。。。

        HandlePacket(cur_str);

    }

}

鎖隻是保護代碼端不被其他線程通路。每個線程都競争這個鎖,競争到了就可以執行我們讓他執行的代碼,這樣就可以控制線程讀寫之間的次序。

繼續閱讀