日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

c++主线程等待子线程结束_简单明了的 Python 多线程来了 | 原力计划

發(fā)布時間:2023/11/27 生活经验 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++主线程等待子线程结束_简单明了的 Python 多线程来了 | 原力计划 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
作者 | 萬里羊責(zé)編 | 王曉曼出品 | CSDN博客線程和進(jìn)程計(jì)算機(jī)的核心是CPU,它承擔(dān)了所有的計(jì)算任務(wù),就像是一座工廠在時刻運(yùn)行。如果工廠的資源有限,一次只能供一個車間來使用,也就是說當(dāng)一個車間開工時其它車間不能工作,也就是一個CPU一次只能執(zhí)行一個任務(wù)。進(jìn)程就好比工廠的車間,它代表CPU所能處理的單個任務(wù)。任一時刻,CPU總是運(yùn)行一個進(jìn)程,其他進(jìn)程處于非運(yùn)行狀態(tài)。當(dāng)然一個車間還有很多工人,他們互相協(xié)同完成一個工作;而線程就好比工廠的工人,一個進(jìn)程可以包含多個線程。線程(Thread)也叫輕量級進(jìn)程,是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,它被包涵在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。線程自己不擁有系統(tǒng)資源,只擁有一點(diǎn)兒在運(yùn)行中必不可少的資源,但它可與同屬一個進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源。一個線程可以創(chuàng)建和撤消另一個線程,同一進(jìn)程中的多個線程之間可以并發(fā)執(zhí)行。多線程與多進(jìn)程通俗易懂的理解就是:
多進(jìn)程:允許多個任務(wù)同時進(jìn)行
多線程:允許單個任務(wù)分成不同的部分運(yùn)行
Python多線程的實(shí)現(xiàn)Python3 通過兩個標(biāo)準(zhǔn)庫 thread(python2中是thread模塊)和 threading 提供對線程的支持。thread 提供了低級別的、原始的線程以及一個簡單的鎖,它相比于 threading 模塊的功能還是比較有限的。threading:
import?threading?#導(dǎo)入threading庫import?timedef?run(n):
????print("task",?n)
????time.sleep(1)?#延時一秒
????print('2s')
????time.sleep(1)
????print('1s')
????time.sleep(1)
????print('0s')
????time.sleep(1)if?__name__?==?'__main__':
????t1?=?threading.Thread(target=run,?args=("t1",))#創(chuàng)建線程1,取名為t1
????t2?=?threading.Thread(target=run,?args=("t2",))#創(chuàng)建線程2,取名為t2
????t1.start()?#開啟線程t1
????t2.start()?#開啟線程t2
輸出結(jié)果:
task?t1
task?t22s2s1s1s0s0s
可以看出先開啟了線程t1,在開啟t2然后每隔一秒打印數(shù)據(jù)。自定義線程通過繼承threading.Thread來自定義線程類,其本質(zhì)是重構(gòu)Thread類中的run方法:
import?threadingimport?timeclass?MyThread(threading.Thread):def?__init__(self,?n):
????????super(MyThread,?self).__init__()??#?重構(gòu)run函數(shù)必須要寫
????????self.n?=?ndef?run(self):
????????print("task",?self.n)
????????time.sleep(1)
????????print('2s')
????????time.sleep(1)
????????print('1s')
????????time.sleep(1)
????????print('0s')
????????time.sleep(1)if?__name__?==?"__main__":
????t1?=?MyThread("t1")
????t2?=?MyThread("t2")
????t1.start()
????t2.start()
輸出結(jié)果:
task?t1
task?t22s2s1s1s0s0s
守護(hù)線程?下面這個例子,使用setDaemon(True)把所有的子線程都變成了主線程的守護(hù)線程,因此當(dāng)主進(jìn)程結(jié)束后,子線程也會隨之結(jié)束。所以當(dāng)主線程結(jié)束后,整個程序就退出了。
import?threadingimport?timedef?run(n):
????print("task",?n)
????time.sleep(1)???????#此時子線程停1s
????print('3')
????time.sleep(1)
????print('2')
????time.sleep(1)
????print('1')if?__name__?==?'__main__':
????t?=?threading.Thread(target=run,?args=("t1",))
????t.setDaemon(True)???#把子進(jìn)程設(shè)置為守護(hù)線程,必須在start()之前設(shè)置
????t.start()
????print("end")
輸出結(jié)果:
task?t1
end
可以看到,t1線程并沒有執(zhí)行完畢,而是直接結(jié)束了。說明設(shè)置子線程為守護(hù)線程之后,主線程結(jié)束了,子線程也立即結(jié)束不再執(zhí)行。程序中不是只創(chuàng)建了一個線程么?怎么會有主線程和子線程呢?其實(shí)呢程序運(yùn)行時就會創(chuàng)建一個線程,而這個線程就是主線程。主線程等待子線程運(yùn)行結(jié)束
import?threadingimport?timedef?run(n):
????print("task",?n)
????time.sleep(1)??????
????print('3')
????time.sleep(1)
????print('2')
????time.sleep(1)
????print('1')if?__name__?==?'__main__':
????t?=?threading.Thread(target=run,?args=("t1",))
????t.setDaemon(True)???#把子進(jìn)程設(shè)置為守護(hù)線程,必須在start()之前設(shè)置
????t.start()
????t.join()?#?設(shè)置主線程等待子線程結(jié)束
????print("end")
輸出結(jié)果:
task?t1321
end
運(yùn)行.join()后的程序表明等待所有線程結(jié)束以后再進(jìn)行.join()之后的操作結(jié)合以上代碼就是,等待t1結(jié)束以后再執(zhí)行end。多線程共享全局變量線程是進(jìn)程的執(zhí)行單元,進(jìn)程是系統(tǒng)分配資源的最小單位,所以在同一個進(jìn)程中的多線程是共享資源的。那么共享資源時就需要用到全局變量。
import?threadingimport?time
num?=?100def?work1():global?numfor?i?in?range(3):
????????num?+=?1
????print("in?work1?num?is?:?%d"?%?num)def?work2():global?num
????print("in?work2?num?is?:?%d"?%?num)if?__name__?==?'__main__':
????t1?=?threading.Thread(target=work1)
????t1.start()
????time.sleep(1)
????t2?=?threading.Thread(target=work2)
????t2.start()
運(yùn)行結(jié)果如下:
in?work1?num?is?:?103in?work2?num?is?:?103
可以看到兩者輸出的結(jié)果是相同的,說明是可以共享全局變量的。互斥鎖由于線程之間是進(jìn)行隨機(jī)調(diào)度,并且每個線程可能只執(zhí)行n條,當(dāng)多個線程同時修改同一條數(shù)據(jù)時可能會出現(xiàn)臟數(shù)據(jù),因而,出現(xiàn)了線程鎖,即同一時刻只允許一個線程執(zhí)行操作。線程鎖用于鎖定資源,可以定義多個鎖, 在下面的實(shí)例中, 當(dāng)你需要獨(dú)占某一資源時,任何一個鎖都可以鎖這個資源,就好比你用不同的鎖都可以把相同的一個門鎖住是一個道理。由于線程之間是進(jìn)行隨機(jī)調(diào)度,如果有多個線程同時操作一個對象,如果沒有很好地保護(hù)該對象,會造成程序結(jié)果的不可預(yù)期,我們也稱此為“線程不安全”。為了方式上面情況的發(fā)生,就出現(xiàn)了互斥鎖(Lock):
import?threading
def?work1():global?A,lock#定義A和lock為全局變量lock.acquire()#上鎖for?i?in?range(5):
????????A+=1
????????print('work1',A)lock.release()#解鎖def?work2():global?A,locklock.acquire()for?i?in?range(5):
????????A+=10
????????print('work2',A)lock.release()if?__name__=='__main__':lock=threading.Lock()#定義鎖
????A=0
????t1=threading.Thread(target=work1)
????t2=threading.Thread(target=work2)
????t1.start()
????t2.start()
????t1.join()
????t2.join()
輸出結(jié)果:
work1?1
work1?2
work1?3
work1?4
work1?5
work2?15
work2?25
work2?35
work2?45
work2?55
可以發(fā)現(xiàn)對兩組數(shù)據(jù)是沒有影響的,感興趣的可以嘗試一下不加鎖會有什么情況。遞歸鎖RLcok類的用法和Lock類一模一樣,但它支持嵌套,在多個鎖沒有釋放的時候一般會使用RLcok類。
import?threading
import?time
def?Func(lock):global?gl_numlock.acquire()
????gl_num?+=?1
????time.sleep(1)
????print(gl_num)lock.release()if?__name__?==?'__main__':
????gl_num?=?0lock?=?threading.RLock()for?i?in?range(10):
????????t?=?threading.Thread(target=Func,?args=(lock,))
????????t.start()
輸出結(jié)果:
1
2
3
4
5
6
7
8
9
10
信號量(BoundedSemaphore類)互斥鎖同時只允許一個線程更改數(shù)據(jù),而Semaphore是同時允許一定數(shù)量的線程更改數(shù)據(jù),比如廁所有3個坑,那最多只允許3個人上廁所,后面的人只能等里面有人出來了才能再進(jìn)去。實(shí)際中博主還沒有用到過,所以理解不是特別透徹。
import?threadingimport?timedef?run(n,?semaphore):
????semaphore.acquire()???#加鎖
????time.sleep(1)
????print("run?the?thread:%s\n"?%?n)
????semaphore.release()?????#釋放if?__name__?==?'__main__':
????num?=?0
????semaphore?=?threading.BoundedSemaphore(5)??#?最多允許5個線程同時運(yùn)行for?i?in?range(22):
????????t?=?threading.Thread(target=run,?args=("t-%s"?%?i,?semaphore))
????????t.start()while?threading.active_count()?!=?1:pass??#?print?threading.active_count()else:
????????print('-----all?threads?done-----')
輸出結(jié)果有點(diǎn)長,就不貼輸出結(jié)果了。事件(Event類)python線程的事件用于主線程控制其他線程的執(zhí)行,事件是一個簡單的線程同步對象,其主要提供以下幾個方法:
  • clear 將flag設(shè)置為“False”;
  • set 將flag設(shè)置為“True”;
  • is_set 判斷是否設(shè)置了flag;
  • wait 會一直監(jiān)聽flag,如果沒有檢測到flag就一直處于阻塞狀態(tài)。
事件處理的機(jī)制:全局定義了一個“Flag”,當(dāng)flag值為“False”,那么event.wait()就會阻塞,當(dāng)flag值為“True”,那么event.wait()便不再阻塞:
import?threadingimport?time
event?=?threading.Event()def?lighter():
????count?=?0
????event.set()?????#初始值為綠燈while?True:if?5?10?:
????????????event.clear()??#?紅燈,清除標(biāo)志位
????????????print("1mred?light?is?on...")elif?count?>?10:
????????????event.set()??#?綠燈,設(shè)置標(biāo)志位
????????????count?=?0else:
????????????print("mgreen?light?is?on...")
????????time.sleep(1)
????????count?+=?1def?car(name):while?True:if?event.is_set():??????#判斷是否設(shè)置了標(biāo)志位
????????????print("[%s]?running..."%name)
????????????time.sleep(1)else:
????????????print("[%s]?sees?red?light,waiting..."%name)
????????????event.wait()
????????????print("[%s]?green?light?is?on,start?going..."%name)
light?=?threading.Thread(target=lighter,)
light.start()
car?=?threading.Thread(target=car,args=("MINI",))
car.start()
這段代碼模擬紅綠燈,很形象。Qthread本以為我學(xué)完了多線程就完事了,就可以將語音和QT界面進(jìn)行整合了。當(dāng)我去實(shí)現(xiàn)的時候發(fā)現(xiàn)問題不是這么簡單,通過語音控制打開一個特定的界面可以實(shí)現(xiàn),但是為什么只要這個特定的界面關(guān)閉了,我語音的線程也就結(jié)束了。困惑了我好久,最后終于在某社區(qū)發(fā)現(xiàn)了答案!原來QT自帶的有Qthread,當(dāng)多線程涉及到界面交互時最好用Qthread來實(shí)現(xiàn)。然后又查閱大量博客,看了大量代碼。在使用繼承QThread的run方法之前需要了解一條規(guī)則:QThread只有run函數(shù)是在新線程里的,其他所有函數(shù)都在QThread生成的線程里
  • QThread只有run函數(shù)是在新線程里的;
  • QThread只有run函數(shù)是在新線程里的;
  • QThread只有run函數(shù)是在新線程里的。
那么我就在網(wǎng)上找到了這個計(jì)時器的例子:
#coding=utf-8
import?sys
from?PyQt5.QtGui?import?*
from?PyQt5.QtWidgets?import?*
from?PyQt5.QtCore?import?*
count?=?0#?工作線程class?WorkThread(QThread):#?pyqtSignal是信號類
????timeout?=?pyqtSignal()??#?每隔一秒發(fā)送一個信號end?=?pyqtSignal()??#?計(jì)數(shù)完成后發(fā)送一個信號def?run(self):while?True:#?休眠1秒self.sleep(1)if?count?==?5:self.end.emit()??#?發(fā)送end信號,調(diào)用和end信號關(guān)聯(lián)的方法breakself.timeout.emit()??#?發(fā)送timeout信號class?Counter(QWidget):def?__init__(self):super(Counter,?self).__init__()self.setWindowTitle("用QThread編寫計(jì)數(shù)器")self.resize(600,?400)
????????layout?=?QVBoxLayout()#?QLCDNumber?用于模擬LED顯示效果,類似于Labelself.lcdNumber?=?QLCDNumber()
????????layout.addWidget(self.lcdNumber)
????????button?=?QPushButton("開始計(jì)數(shù)")
????????layout.addWidget(button)self.workThread?=?WorkThread()self.workThread.timeout.connect(self.countTime)self.workThread.end.connect(self.end)
????????button.clicked.connect(self.work)self.setLayout(layout)def?countTime(self):
????????global?count
????????count?+=?1self.lcdNumber.display(count)def?end(self):
????????QMessageBox.information(self,?'消息',?'計(jì)數(shù)結(jié)束',?QMessageBox.Ok)
????????global?count
????????count?=0def?work(self):self.workThread.start()if?__name__?==?"__main__":
????app?=?QApplication(sys.argv)
????main?=?Counter()
????main.show()
????sys.exit(app.exec_())
點(diǎn)擊開始計(jì)時就會出現(xiàn)類似LCD的顯示,計(jì)時到5秒結(jié)束后彈窗提醒。運(yùn)行結(jié)果如下:通過這個例程讓我對Qthread有了更好的理解,經(jīng)管理解的不是特別透徹但是我知道怎么來改出來我想用的代碼。之前提到的打開窗口線程阻塞,關(guān)閉窗口線程重啟,其實(shí)這個計(jì)時器是一個很好的例子,但是關(guān)于線程阻塞.wait不好使。我的方法是定義一個全局變量mode=0(用來判斷是否需要阻塞線程),如果窗口打開后那么給這個全局賦值mode=1,在run函數(shù)里對這個mode進(jìn)行判斷,如果mode等于1那么可以用一個循環(huán)來延時實(shí)現(xiàn)。
if?mode:while(mode):self.sleep(1)
當(dāng)窗口關(guān)閉以后給mode 賦值等于0通過這種方法可以實(shí)現(xiàn),很多小伙伴又會問怎么判斷窗口打開和關(guān)閉,其實(shí)在自己寫的窗口函數(shù)最前面加mode=1和最后面mode=0就可以了不用進(jìn)行判斷。版權(quán)聲明:本文為CSDN博主「萬里羊」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。原文鏈接:https://blog.csdn.net/weixin_44895651/article/details/105877358

更多精彩推薦

?那些被大數(shù)據(jù)時代拋棄的人

?反轉(zhuǎn)!物聯(lián)網(wǎng)火爆,開發(fā)者卻太難了!

?小米回應(yīng)林斌退休傳聞;哈工大等高校被禁止使用 MATLAB;統(tǒng)信軟件 UOS20 SP1 系統(tǒng)升級| 極客頭條

?一篇與眾不同的 String、StringBuilder 和 StringBuffer 詳解

?利用 AssemblyAI 在 PyTorch 中建立端到端的語音識別模型

?贈書 | 供應(yīng)鏈金融模式有哪些?區(qū)塊鏈在供應(yīng)鏈金融中如何應(yīng)用?

你點(diǎn)的每個“在看”,我都認(rèn)真當(dāng)成了喜歡

總結(jié)

以上是生活随笔為你收集整理的c++主线程等待子线程结束_简单明了的 Python 多线程来了 | 原力计划的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。