轉自
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);
}
}
鎖隻是保護代碼端不被其他線程通路。每個線程都競争這個鎖,競争到了就可以執行我們讓他執行的代碼,這樣就可以控制線程讀寫之間的次序。