程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 多線程同步-主線程等待所有子線程完成案例

多線程同步-主線程等待所有子線程完成案例

編輯:C++入門知識

有時候我們會遇到這樣的問題:做一個大的事情可以被分解為做一系列相似的小的事情,而小的事情無非就是參數上有可能不相同而已!

此時,如果不使用線程,我們勢必會浪費非常多的時間來完成整個大的事情,而使用線程的話將會存在這樣的問題:

主線程啟動所有子線程並發執行後主線程就直接返回了,導致外部函數判讀整個大的事情完成了,但是實際上並沒有完成!


針對以上情況我想我會采用多線程方式執行同時解決主線程等待子線程的問題。如圖:

\

在這裡我使用Java進行案例分析。<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+ytfPyL2owaLSu7j2z9+zzLncwO3A4KOs08PT2sb0tq/L+dPQ19PP37PMus21yLT9y/nT0NfTz9+zzM3qs8mjrNTa1eLA77K7yrnTw9Ddw9/Su7bOyrG85Lrz0a27t7zssuK1xLe9yr2jqM/7usRDVVDNrMqxz/u6xMqxvOSjrMirsr/N6rPJyrG85LK7ubu8sMqxtcjIsbXjo6mju7b4ysfKudPDtci0/cHZvecmIzIwNTQwO7XEt73KvaGjVGhyZWFkTWFuYWdlci5qYXZhyOfPwqO6PC9wPgo8cD48cHJlIGNsYXNzPQ=="brush:java;">public class ThreadManager implements NotifyInterface { private final Object mLock = new Object(); private int mCount = 0; private int endCount = 0; public ThreadManager(int count) { System.out.println("Manager In."); this.mCount = count; this.addThread(); synchronized (mLock) { while (true) { if (checkEnd()) break; try { mLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println("Manager Out."); } private void addThread() { System.out.println("Manager addThread()."); for (int i = 1; i <= mCount; i++) { ThreadDoThing dThread = new ThreadDoThing(i, "T" + i, this); // Start dThread.start(); } } private boolean checkEnd() { boolean bFlag = false; bFlag = endCount >= mCount; System.out.println("Manager checkEnd().Return is:" + bFlag); return bFlag; } @Override public void runEnd() { synchronized (mLock) { ++endCount; mLock.notifyAll(); } } }
此類集成自:NotifyInterface接口,NotifyInterface是用於子線程通知主線程自己已經完成工作所用類,ThreadManager實例化時將傳入一個int值,用於設置啟動的子線程數,當然這裡是為了簡單介紹所以采用的這樣的方式,實際情況可能更加復雜。

在實例化後 進入構造方法,此時將會啟動子線程,啟動後進入循環等待中,當檢測到所有子線程完成時就退出循環,沒有就將進入臨界值等待,直到通過接口通知主線程完成時將會通知臨界值一次,此時循環將會執行一次,如果不滿足退出條件將繼續等待臨界值。直到滿足為止。

NotifyInterface接口如下:

public interface NotifyInterface {
	
	public abstract void runEnd();

}

測試用的子線程ThreadDoThing.java如下:

public class ThreadDoThing extends Thread {
	private NotifyInterface mInterface = null;
	private int mId = 0;
	private String mArgs = null;

	public ThreadDoThing(int id, String args, NotifyInterface iface) {
		this.mId = id;
		this.mArgs = args;
		this.AddInterface(iface);
	}

	public void AddInterface(NotifyInterface iface) {
		this.mInterface = iface;
	}

	@Override
	public void run() {
		System.out.println("ThreadDoThing Id is:" + this.mId + " Args is:" + this.mArgs);
		System.out.println(this.mId + ":Doing...");

		int sleepTime = (int) (Math.random() * 1000);

		try {
			Thread.sleep(sleepTime);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(this.mId + ":SleepTime is:" + sleepTime);

		this.notifyEnd();

		System.out.println(this.mId + ":Do End.");
	}

	private void notifyEnd() {
		if (this.mInterface != null)
			this.mInterface.runEnd();

		System.out.println(this.mId + ":Notify End.");
	}
}

此類繼承自Thread類,可直接重寫Run()方法完成所做工作!

在工作中,我使用了隨機一個1s內的休眠來代替所做工作的時間,完成後調用接口通知完成。


測試方法如下:

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ThreadManager manager = new ThreadManager(10);
	}

測試結果:

Manager In.
Manager addThread().
ThreadDoThing Id is:1 Args is:T1
ThreadDoThing Id is:2 Args is:T2
2:Doing...
1:Doing...
ThreadDoThing Id is:3 Args is:T3
ThreadDoThing Id is:4 Args is:T4
3:Doing...
4:Doing...
ThreadDoThing Id is:5 Args is:T5
5:Doing...
ThreadDoThing Id is:6 Args is:T6
Manager checkEnd().Return is:false
ThreadDoThing Id is:8 Args is:T8
ThreadDoThing Id is:7 Args is:T7
8:Doing...
ThreadDoThing Id is:9 Args is:T9
9:Doing...
6:Doing...
ThreadDoThing Id is:10 Args is:T10
7:Doing...
10:Doing...
3:SleepTime is:111
3:Notify End.
3:Do End.
Manager checkEnd().Return is:false
5:SleepTime is:142
5:Notify End.
Manager checkEnd().Return is:false
5:Do End.
4:SleepTime is:199
4:Notify End.
Manager checkEnd().Return is:false
4:Do End.
7:SleepTime is:342
7:Notify End.
Manager checkEnd().Return is:false
7:Do End.
10:SleepTime is:346
10:Notify End.
Manager checkEnd().Return is:false
10:Do End.
6:SleepTime is:397
6:Notify End.
Manager checkEnd().Return is:false
6:Do End.
9:SleepTime is:468
9:Notify End.
Manager checkEnd().Return is:false
9:Do End.
1:SleepTime is:475
1:Notify End.
Manager checkEnd().Return is:false
1:Do End.
2:SleepTime is:686
Manager checkEnd().Return is:false
2:Notify End.
2:Do End.
8:SleepTime is:828
8:Notify End.
Manager checkEnd().Return is:true
8:Do End.
Manager Out.

實際情況可能更加復雜,甚至子線程下還有更多的子線程!

具體情況大家可以衍生考慮,檢測是否全部返回也可以有多種方式甚至設置添加一個定時器之類的。

以後有時間畫一個詳細點的圖!


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved