vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
vb@rchiv Offline-Reader - exklusiv auf der vb@rchiv CD Vol.4  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2024
 
zurück

 Sie sind aktuell nicht angemeldet.Funktionen: Einloggen  |  Neu registrieren  |  Suchen

VB.NET - Fortgeschrittene
Threadpool: Beendigung aller Threads feststellen 
Autor: Manfred X
Datum: 17.09.14 15:41

Hallo!

Ich stelle eine große Anzahl von Threads in den Threadpool (QueueUserWorkItem),
von denen maximal 20 (SetMaxThreads) gleichzeitig ausgeführt werden können.

Wie kann man zuverlässig festellen, ob bereits alle Threads erledigt worden sind?

Bis jetzt mache ich das so, daß jeder Thread beim Einstellen in den Threadpool
in einer Registrierungsklasse angemeldet wird und sich beim Beendigen abmeldet.
Sobald diese Registratur "leer" ist, wird von ihr ein entsprechendes Ereignis
ausgelöst. Es scheint zu funktionieren, aber: Ist das der richtige Weg?













Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Threadpool: Beendigung aller Threads feststellen 
Autor: ModeratorDaveS (Moderator)
Datum: 17.09.14 17:40

Das habe ich auch so ähnlich gemacht.

________
Alle Angaben ohne Gewähr. Keine Haftung für Vorschläge, Tipps oder sonstige Hilfe, falls es schiefgeht, nur Zeit verschwendet oder man sonst nicht zufrieden ist

Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Threadpool: Beendigung aller Threads feststellen 
Autor: Manfred X
Datum: 17.09.14 17:49

Hallo!

Gefunden habe ich das Vorgehen mit "WaitHandles":
http://msdn.microsoft.com/de-de/library/system.threading.waithandle%28v=vs.100%29.aspx
Dieses Klasse hat aber den Nachteil, daß der Thread, der den Threadpool "füllt", bis zum
Beendigen aller Threads angehalten wird.


Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Threadpool: Beendigung aller Threads feststellen 
Autor: ModeratorDaveS (Moderator)
Datum: 17.09.14 20:19

Bei meinem ThreadManager Code werden Threads durch von BaseWorkItem abgeleiteten Klassen repräsentiert. ThreadManager macht so einiges um verschiedene Arten von Threads zu verwalten. Ist aber alles sehr alt und nicht so OOP-konform wie mir jetzt lieb wäre, und wahrscheinlich sowieso nicht mehr wirklich zeitgemäß.
using System;
using System.Threading;
using System.Collections;
using System.Collections.Specialized;
using System.Web;
using System.Diagnostics;
using System.Globalization;
 
using DSNTS.BaseServices;
 
namespace DSNTS.ExtendedServices
{
	/// <summary>
	/// ThreadManager encapsulates thread processing for all kinds of threads
	/// </summary>
	[CodeCategory("ThreadMgr")]
	public sealed class SThreadManager : IObjectStats
	{		
		// This is the global thread manager singleton code
		private static SThreadManager __threadMgr = null;
 
		public static void CreateThreadManager(int reservedThreadsCount, int _
  maxSystemThreads)
		{
			if (__threadMgr==null) __threadMgr = new SThreadManager( _
  reservedThreadsCount, maxSystemThreads);
		} // CreateThreadManager()
 
		public static SThreadManager ThreadManager {get{return __threadMgr;}}
 
		// Allow only a single instance of ThreadManager
		private SThreadManager() {}
 
		private SThreadManager(int reservedThreadsCount, int maxSystemThreads)
		{
			_reservedThreadsCount = reservedThreadsCount;
			_maxSystemThreads = maxSystemThreads;
			if (SObjectStats.ObjectStats!=null) SObjectStats.ObjectStats.RegisterObject( _
  "ThreadManager", this as IObjectStats);
		}
 
		private static int _maxSystemThreads = 10;
 
		public static long GetWorkItemId()
		{
			return Interlocked.Increment(ref _workItemNum);
		} // GetWorkItemId()
 
		// Application closedown flag and event
		private  bool _closeDown = false;
		public bool CloseDown
		{
			get {return _closeDown;}
		}
		ManualResetEvent _cdevent = new ManualResetEvent(false);
		ManualResetEvent _cdevent1 = null;
 
		// Queue of waiting work items
		private Queue _workItems = new Queue(100);
 
		// System/timer/pool threads running
		private Hashtable _runningThreads = new Hashtable(_maxSystemThreads);
 
		// Timer threads
		private Hashtable _timerThreads = new Hashtable(5);
 
		// Stats stuff
 
		// Threading Counters
		private short _runningSystemThreadsCount = 0;
		private short _maxRunningSystemThreadsCount = 0;
 
		private short _runningThreadsCount = 0;
		private short _maxRunningThreadsCount = 0;
 
		// Each work item gets a unique id (number)
		private static long _workItemNum = 0;
 
		// Note: queued worker count is the count of threads which have been passed _
  to threadpool 
		// but have not yet started execution.
		private int _queuedWorkerThreadsCount = 0;
		private int _maxQueuedWorkerThreadsCount = 0;
		private int _runningWorkerThreadsCount = 0;
		private int _maxRunningWorkerThreadsCount = 0;
		private int _maxHeldWorkerThreadsCount = 0;
		private int _queuedTimerThreadsCount = 0;
		private int _maxQueuedTimerThreadsCount = 0;
		private int _runningTimerThreadsCount = 0;
		private int _maxRunningTimerThreadsCount = 0;
		private int _reservedThreadsCount = 2;
 
		// Application post closedown (interval in seconds)
		public void DoCloseDown1(int interval)
		{
			if (TC.TraceOn) TC.Trace(1, "Thread manager stopping active threads at:" & _
  "{tsms}");
			_closeDown = true;
			ListActiveThreads();
			lock(_runningThreads.SyncRoot)
			{
				if (TC.TraceOn) TC.Trace(1, "Thread manager running count 1: {0}", _
  _runningSystemThreadsCount);
				foreach(DictionaryEntry de in _runningThreads)
				{
					try
					{
						if (de.Value is BaseThread)
						{
							BaseThread ct = (BaseThread)de.Value;
							ct.CloseDown();
						}
					}
					catch(System.Exception ex)
					{EH.UE(ex);}
				}
				if (TC.TraceOn) TC.Trace(1, "Thread manager running count 2: {0}", _
  _runningSystemThreadsCount);
				_cdevent.Set();
				scheduleQueuedPoolThreads();
				foreach(DictionaryEntry de in _timerThreads)
				{
					if (de.Value is TimerThread)
					{
						TimerThread ct = (TimerThread)de.Value;
						ct.KillTimer();
					}
				} 
				_timerThreads.Clear();
				ListActiveThreads();
				if (_runningThreadsCount>0) _cdevent1 = new ManualResetEvent(false);
				if (TC.TraceOn) TC.Trace(1, "Thread manager running count 3: {0}", _
  _runningSystemThreadsCount);
			} // lock()
 
			// Wait for all threads to end
			if (_cdevent1!=null) _cdevent1.WaitOne(interval*1000, false);
 
			if (TC.TraceOn) 
			{
				lock(_runningThreads.SyncRoot)
				{
					ListActiveThreads();
					TC.Trace(1, "Thread manager running count 4: {0}", _
  _runningSystemThreadsCount);
					foreach(DictionaryEntry de in _runningThreads)
					{
						if (de.Value is SystemThread)
						{
							BaseThread ct = (BaseThread)de.Value;
							TC.Trace(1, "Thread manager closedown (1) still running: {0}", _
  ct.WI.ProcessId);
						}
					}
				}
				TC.Trace(1, "Thread manager closedown complete at:" & _
  "{tsms}"+DateTime.Now.ToLongTimeString());
			}			
		} // DoCloseDown1()
 
		public void DoCloseDown2(int interval)
		{
			_closeDown = true;
			if (TC.TraceOn) TC.Trace(1, "Thread manager aborting active threads at:" & _
  "{tsms}");
 
			lock(_runningThreads.SyncRoot)
			{
				foreach(DictionaryEntry de in _runningThreads)
				{
					if (de.Value is SystemThread)
					{
						SystemThread cst = (SystemThread)de.Value;
						cst.Abort();
					}
				}
				if (_runningThreadsCount>0) _cdevent1 = new ManualResetEvent(false);
				if (TC.TraceOn) TC.Trace(1, "Thread manager aborting active threads" & _
  "complete at: {tsms}");
			}
 
			// Wait for all threads to exit
			if (_cdevent1==null) _cdevent1.WaitOne(interval*1000, false);
 
			ListActiveThreads();
			if (TC.TraceOn) TC.Trace(1, "Thread manager running count 5: {0}", _
  _runningSystemThreadsCount);
		} // DoCloseDown2()
 
		// General WorkItem Thread Scheduler
		public BaseThread RunWorkItem(IWorkItem wi)
		{
			switch(wi.ThreadType)
			{
				case WorkItemThreadType.Pool:
					IPoolWorkItem pwi = wi as IPoolWorkItem;
					if (pwi==null) return null;
					QueueWorkItem(pwi);
					break;
				case WorkItemThreadType.System:
					ISystemWorkItem swi = wi as ISystemWorkItem;
					if (swi==null) return null;
					return StartSystemThread(wi, swi.Start, swi.Wait);
				case WorkItemThreadType.Timed:
					ITimedWorkItem twi = wi as ITimedWorkItem;
					if (twi==null) return null;
					return StartTimerThread(wi, twi.DelayMilliseconds, twi.RepeatMilliseconds);
			}
			return null;
		}
 
		// System Threads
 
		// Start a ThreadManager System Thread
		// A system thread is (meant to be) a permanently running thread
		// The number of such threads is limited (for performance reasons)
		// to the _maxSystemThreads value defined somewhere above.
 
		// Each such thread is named by its WorkItem.ProcessId value, and each such _
  thread
		// should therefore have a unique process id.
		public SystemThread StartSystemThread(IWorkItem wi, bool start, bool wait)
		{
			SystemThread t = null;
 
			// Add thread to collection
			lock(_runningThreads.SyncRoot)
			{
				if (_runningThreads[wi.ProcessId]==null)
				{
					if (_runningSystemThreadsCount<_maxSystemThreads)
					{
						int tn = ++_runningSystemThreadsCount;
						if (tn>_maxRunningSystemThreadsCount)
							_maxRunningSystemThreadsCount = _runningSystemThreadsCount;
						tn = ++_runningThreadsCount;
						if (tn>_maxRunningThreadsCount)
							_maxRunningThreadsCount = _runningThreadsCount;
 
						t = new SystemThread(wi);
						if (TC.TraceOn) TC.Trace(1, "System thread created: {0} current count:" & _
  "{1} {tsms}",wi, _runningSystemThreadsCount);
						_runningThreads[wi.ProcessId] = t;
						t.T.Priority = wi.Priority;
					}
					else
						if (TC.TraceOn) TC.Trace(1, "System thread request: {0} would exceed max" & _
  "count: {1} {tsms}", wi, _runningSystemThreadsCount);
				}
				else
					if (TC.TraceOn) TC.Trace(1, "System thread request: {0} already running:" & _
  "{1} {tsms}", wi, _runningSystemThreadsCount);
			}
			if (t==null)
				throw new OperationException("Invalid system thread request for: {0}", wi);
			if (start) t.Start();
			if (wait) t.Wait();
			return t;
		} // StartSystemThread()
 
		// Start of system thread registration		
		internal void RegisterSystemThread(SystemThread cst)
		{
			IWorkItem wi = cst.WI;
			if (wi==null) return;
			InitThread(wi);
			if (TC.TraceOn) TC.Trace(1, "System thread started: {0} current count: {1}" & _
  "{tsms}", wi, _runningSystemThreadsCount);				
		} // RegisterSystemThread()
 
		// End of system thread deregistration		
		internal void DeregisterSystemThread(SystemThread cst)
		{
			IWorkItem wi = cst.WI;
			if (wi==null) return;
			lock(_runningThreads.SyncRoot)
			{
				try
				{
					_runningThreads.Remove(wi.ProcessId);
				}
				finally
				{
					_runningSystemThreadsCount--;
					_runningThreadsCount--;
					if (_closeDown&&(_runningThreadsCount==0)&&(_cdevent1!=null)) _
  _cdevent1.Set();
					if (TC.TraceOn) TC.Trace(1, "System thread ended {0} current count: {1}" & _
"{tsms}", wi, _runningSystemThreadsCount);
					TermThread(wi);
				}
			}
		} // DeregisterSystemThread()
 
		// Common thread start/end
		private void InitThread(IWorkItem wi)
		{
			if (wi.Trace) TC.InitThreadContext(wi.ContextData);
		} // InitThread()
 
		private void TermThread(IWorkItem wi)
		{
			if (wi.Trace) TC.TermThreadContext();
		} // TermThread()
 
		// Determine if a system thread is running
		public bool IsSystemThreadRunning(string processId)
		{
			lock(_runningThreads.SyncRoot)
			{
				return _runningThreads[processId]!=null;
			}
		} // IsSystemThreadRunning()
 
		// Wait for a while
		public void ThreadWait(int seconds)
		{
			_cdevent.WaitOne(seconds*1000, false);
		} // ThreadWait()
 
		// Threadpool Threads
 
		// Schedule a unit of work on a threadpool thread
		public void QueueWorkItem(IWorkItem wi)
		{
			IPoolWorkItem pwi = wi as IPoolWorkItem;
			if (pwi!=null&&pwi.PassThrough)
				// if passthru from another threadpool thread just call DoWork()
				wi.DoWork();
			else
			{
				if (_closeDown) return;
				PoolThread cpt = new PoolThread(wi);
 
				// Queue a threadpoool item
				lock(_runningThreads.SyncRoot)
				{
					if (pwi!=null&&pwi.ImmediateThread)
					{
						// If system option start thread immediately
						if (TC.TraceOn) TC.Trace(1, "Queue WorkItem: {0}", wi);
						incQWC();
						cpt.Schedule();
					}
					else
					{
						// otherwise put it on queue
						_workItems.Enqueue(cpt);
						if (wi.Trace&&TC.TraceOn) TC.Trace(1, "Queue WorkItem held thread count:" & _
  "{0}", _workItems.Count);
						if (_workItems.Count>_maxHeldWorkerThreadsCount)
						{
							_maxHeldWorkerThreadsCount++;
							if (wi.Trace&&TC.TraceOn) TC.Trace(1, "Queue WorkItem max held thread" & _
  "count: {0}", _maxHeldWorkerThreadsCount);
						}
 
						// and see if anything can be scheduled now
						try
						{
							scheduleQueuedPoolThreads();
						}
						catch(System.Exception ex)
						{EH.UE(ex);}
					}
				}
			}
		} // QueueWorkItem()
 
		// Start of worker thread registration		
		internal void RegisterWorker(PoolThread cpt)
		{
			IWorkItem wi = cpt.WI;
			if (wi==null) return;			
 
			InitThread(wi);
 
			lock(_runningThreads.SyncRoot)
			{
				_runningWorkerThreadsCount++;
				_queuedWorkerThreadsCount--;
 
				string id = wi.ProcessId+cpt.T.GetHashCode().ToString( _
  CultureInfo.InvariantCulture);
				_runningThreads[id] = cpt;
				int tn = ++_runningThreadsCount;
				if (tn>_maxRunningThreadsCount)
					_maxRunningThreadsCount = _runningThreadsCount;
 
				if (TC.TraceOn)
				{
					TC.Trace(1, "Work thread started: {0}", wi);
					TC.Trace(1, "Activeworker count: {0}", _runningWorkerThreadsCount);
					TC.Trace(1, "Queuedworker count: {0}", _queuedWorkerThreadsCount);
				}
			}
		} // RegisterWorker()
 
		// End of worker thread deregistration		
		internal void DeregisterWorker(PoolThread cpt)
		{
			IWorkItem wi = cpt.WI;
			if (wi==null) return;
			lock(_runningThreads.SyncRoot)
			{
				_runningWorkerThreadsCount--;
				_runningThreadsCount--;
				if (_closeDown&&(_runningThreadsCount==0)&&(_cdevent1!=null)) _cdevent1.Set( _
  );
				string id = wi.ProcessId+cpt.T.GetHashCode().ToString( _
CultureInfo.InvariantCulture);
				if (TC.TraceOn) TC.Trace(1, "Worker thread ended: {0}", wi);
				_runningThreads.Remove(id);
				try
				{
					scheduleQueuedPoolThreads();
				}
				catch(System.Exception ex)
				{EH.UE(ex);}
				TC.Trace(1, "Activeworker count: {0}", _runningWorkerThreadsCount);
				TC.Trace(1, "Queuedworker count: {0}", _queuedWorkerThreadsCount);
			}
			TermThread(wi);
		} // DeregisterWorker()
 
		// Increment queued worker count
		private void incQWC()
		{
			_queuedWorkerThreadsCount++;
			TC.Trace(1, "Queuedworker count: {0}", _queuedWorkerThreadsCount);
			if (_queuedWorkerThreadsCount>_maxQueuedWorkerThreadsCount)
			{
				_maxQueuedWorkerThreadsCount++;			
				TC.Trace(1, "MaxQueuedworker count: {0}", _maxQueuedWorkerThreadsCount);
			}
		}
 
		// Private schedule thread(s) in the waiting queue
		// (Must be invoked from within lock(_runningThreads.SyncRoot))
		private void scheduleQueuedPoolThreads()
		{
			// We assume this is called by another threadpool thread so use _
  availableThreads+1
			// to decide if we can schedule another thread. The only alternative would _
be if this was called from
			// a ThreadManager SystemThread, but we do not (yet) cater for this _
possibility.
			while ((availableThreads()+1)>_reservedThreadsCount&&_workItems.Count>0)			
			{
				PoolThread cpt = (PoolThread)_workItems.Dequeue();
				if (!_closeDown)  // Flush entries if closedown
				{
					if (TC.TraceOn) TC.Trace(1, "Scheduling: {0}", cpt.WI);
					incQWC();
					cpt.Schedule();
				}
			}
		} // scheduleQueuedPoolThreads()
 
		// Public schedule thread(s) in the waiting queue
		// This may be called for example at end of web request thread.
		public void ScheduleQueuedPoolThreads()
		{
			lock(_runningThreads.SyncRoot)
			{
				scheduleQueuedPoolThreads();
			}
		} // ScheduleQueuedPoolThreads()
 
		// Get available threadpool threads
		// Determine the clr available threadpool threads
		private int availableThreads()
		{
			int available_threads;
			int cpta;
			ThreadPool.GetAvailableThreads(out available_threads, out cpta);
			if (TC.TraceOn) TC.Trace(1, "Available worker threads: {0}", _
  available_threads);
			return available_threads;
		} // availableThreads()
 
		// Timer threads
 
		// Start a timer (millisecond units)
		public TimerThread StartTimerThread(IWorkItem wi, int delayMS, int repeatMS)
		{
			if (TC.TraceOn) TC.Trace(1, "Starting timer thread: {0}", wi);
 
			if ((_timerThreads[wi.ProcessId])!=null)
				throw new OperationException("Invalid timer threading request for: {0}", _
  wi);
			lock(_runningThreads.SyncRoot)
			{
				TimerThread ctt = new TimerThread(wi, delayMS, repeatMS);
 
				_timerThreads[wi.ProcessId] = ctt;
				int tn = _queuedTimerThreadsCount++;
				if(tn>_maxQueuedTimerThreadsCount)
					_maxQueuedTimerThreadsCount = tn;
				if (TC.TraceOn) TC.Trace(1, "Queued timer threads: {0}", _
  _queuedTimerThreadsCount);				
				return ctt;
			}
		} // StartTimerThread()
 
		// Stop a timer
		internal void StopTimerThread(TimerThread ctt)
		{
			IWorkItem wi = ctt.WI;
			if (wi==null) return;
			if (TC.TraceOn) TC.Trace(1, "Stopping timer thread: {0}", wi);
			try
			{
				ctt.KillTimer();
			}
			catch(System.Exception ex)
			{EH.UE(ex);}
			if(_timerThreads[wi.ProcessId]==null) return;
			lock(_runningThreads.SyncRoot)
			{
				_timerThreads.Remove(wi.ProcessId);
				_queuedTimerThreadsCount--;
				if (TC.TraceOn) TC.Trace(1, "Queued timer threads: {0}", _
  _queuedTimerThreadsCount);				
			}
		} // StopTimerThread()
 
		// Start of timer thread registration		
		internal void RegisterTimer(TimerThread ctt)
		{
			IWorkItem wi = ctt.WI;
			if (wi==null) return;
			lock(_runningThreads.SyncRoot)
			{
				_runningTimerThreadsCount++;
				if (_runningTimerThreadsCount>_maxRunningTimerThreadsCount)
					_maxRunningTimerThreadsCount++;
				int tn = ++_runningThreadsCount;
				if (tn>_maxRunningThreadsCount)
					_maxRunningThreadsCount = _runningThreadsCount;
				string id = wi.ProcessId+ctt.T.GetHashCode().ToString( _
  CultureInfo.InvariantCulture);
				_runningThreads[id] = ctt;
				InitThread(wi);
				if (TC.TraceOn) TC.Trace(1, "Timer thread starting: {0} {tsms}", wi);
			}
		} // RegisterTimer()
 
		// End of timer thread deregistration		
		internal void DeregisterTimer(TimerThread ctt)
		{
			IWorkItem wi = ctt.WI;
			if (wi==null) return;
			lock(_runningThreads.SyncRoot)
			{
				_runningTimerThreadsCount--;
				_runningThreadsCount--;
				if (_closeDown&&(_runningThreadsCount==0)&&(_cdevent1!=null)) _cdevent1.Set( _
  );
				string id = wi.ProcessId+ctt.T.GetHashCode().ToString( _
CultureInfo.InvariantCulture);
				_runningThreads.Remove(id);
				if (TC.TraceOn) TC.Trace(1, "Timer thread ending: {0} {tsms}", wi);
				TermThread(wi);
			}
		} // DeregisterTimer()
 
		// Test! Routine to list active threads
		public void ListActiveThreads()
		{
			if (!TC.TraceOn) return; 
			lock(_runningThreads.SyncRoot)
			{
				TC.Trace(1, "Active threads: {0}/{1}", _runningSystemThreadsCount, _
  _runningThreads.Count);
				foreach(DictionaryEntry de in _runningThreads)
				{
					BaseThread ct = (BaseThread)de.Value;
					if (ct.T!=null&&ct.WI!=null)
						TC.Trace(1, "Thread: {0} {1}",ct.T.GetHashCode(), ct.WI);
					else
						TC.Trace(1, "Thread: ???? work item ???? id ????");
				} 
			}
		} // ListActiveThreads()
 
		// Test! Routine to list some thread data
		public void ListThreadData(string at, BaseThread ct)
		{
			if (TC.TraceOn) TC.Trace(1, "At: {0} {1} data current: {2} ct.T: {3}",
									at,
									ct.WI!=null?ct.WI.ToString():"No Work Item",
									Thread.CurrentThread.GetHashCode(),
									ct.T!=null?ct.T.GetHashCode().ToString( _
  CultureInfo.InvariantCulture):"no thread in ct.T");
		}
 
		// Statistics Routines
 
		// Thread statistics properties
		public  long HeldWorkerThreadsCount
		{
			get 
			{
				lock(_runningThreads.SyncRoot)
				{
					return _workItems.Count;
				}
			}
		}
 
		public  long MaxHeldWorkerThreadsCount
		{
			get {return _maxHeldWorkerThreadsCount;}
		}
 
		public  long TotalWorkItemsProcessed
		{
			get {return _workItemNum;}
		}
 
		public  long QueuedWorkerThreadsCount
		{
			get {return _queuedWorkerThreadsCount;}
		}
 
		public  long RunningWorkerThreadsCount
		{
			get {return _runningWorkerThreadsCount;}
		}
 
		public  long MaxQueuedWorkerThreadsCount
		{
			get {return _maxQueuedWorkerThreadsCount;}
		}
 
		public  long MaxRunningWorkerThreadsCount
		{
			get {return _maxRunningWorkerThreadsCount;}
		}
 
		public  long RunningSystemThreadsCount
		{
			get {return _runningSystemThreadsCount;}
		}
 
		public  long MaxRunningSystemThreadsCount
		{
			get {return _maxRunningSystemThreadsCount;}
		}
 
		public  long RunningThreadsCount
		{
			get {return _runningThreadsCount;}
		}
 
		public  long MaxRunningThreadsCount
		{
			get {return _maxRunningThreadsCount;}
		}
 
		public  long QueuedTimerThreadsCount
		{
			get {return _queuedTimerThreadsCount;}
		}
 
		public  long MaxQueuedTimerThreadsCount
		{
			get {return _maxQueuedTimerThreadsCount;}
		}
 
		public  long RunningTimerThreadsCount
		{
			get {return _runningTimerThreadsCount;}
		}
 
		public  long MaxRunningTimerThreadsCount
		{
			get {return _maxRunningTimerThreadsCount;}
		}
 
		// Interface IObjectStats	
		public void GetObjectStatistics(string prefix)
		{
			SObjectStats.ObjectStats.Add(prefix, _
  "ThreadManager:Total/TimerThreadObjectsCount", _timerThreads.Count);
			SObjectStats.ObjectStats.Add(prefix, _
"ThreadManager:Total/RunningThreadObjectsCount", _runningThreads.Count);
			SObjectStats.ObjectStats.Add(prefix, _
"ThreadManager:Total/QueuedWorkItemObjectsCount", _workItems.Count);
		}	
	} // class ThreadManager
}

________
Alle Angaben ohne Gewähr. Keine Haftung für Vorschläge, Tipps oder sonstige Hilfe, falls es schiefgeht, nur Zeit verschwendet oder man sonst nicht zufrieden ist

Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Threadpool: Beendigung aller Threads feststellen 
Autor: Kuno60
Datum: 17.09.14 22:22

Hallo,

ab FW 4.5 kann man es auch so machen:
  Sub Tasks()
    Dim tasklist As New List(Of Task)
    tasklist.Add(Task.Run(AddressOf Task1))
    tasklist.Add(Task.Run(AddressOf Task2))
    tasklist.Add(Task.Run(AddressOf Task3))
    Task.WaitAll(tasklist.ToArray)
    MsgBox("Alle Tasks wurden beendet.")
  End Sub
Die Tasks laufen im Threadpool.
Es gibt noch viele weitere Möglichkeiten, siehe hier:
http://msdn.microsoft.com/de-de/library/hh191443.aspx
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Threadpool: Beendigung aller Threads feststellen 
Autor: Manfred X
Datum: 17.09.14 22:50

Hallo!

Ich wollte vermeiden, einen Thread anzuhalten (Waitall).

Die Async/Await-Variante ist für einzelne Aktivitäten eine interessante
Neuerung - aber ich benötige Multithreading (tausende Threads!)

Die von mir oben skizzierte Methode funktioniert nach bisherigen Tests
sehr gut. Zu beachten ist, daß die gepoolten Threads im "Hintergrund"
laufen. Man muß verhindern, daß sie (z.B. durch GUI-Aktivitäten)
"hard" gecancelt werden.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Threadpool: Beendigung aller Threads feststellen 
Autor: Manfred X
Datum: 18.09.14 10:15

Das muß ich erst verdauen ...

Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Threadpool: Beendigung aller Threads feststellen 
Autor: Kuno60
Datum: 18.09.14 15:15

Hallo Manfred,

Async/Await ist nicht immer die beste Variante, aber in vielen Fällen eine sehr einfache Variante.

Das erste Beispiel von mir, war nicht so ideal.
Hier ein Beispiel, bei dem der Hauptthread nicht blockiert wird.
So hab ich es schon in einigen Programmen verwendet.
  Async Function Tasks() As Task
    Dim tasks(2) As Task
    tasks(0) = Task.Run(AddressOf Task1)
    tasks(1) = Task.Run(AddressOf Task2)
    tasks(2) = Task.Run(AddressOf Task3)
    Await Task.WhenAll(tasks)
    MsgBox("Alle Tasks wurden beendet.")
  End Function
Mit diesem Code lese ich eine 200 MB große XML-Datei mit einem XmlReader ein. Durch die Aufteilung auf 4 Tasks verkürzt sich die Lesezeit auf 2 Sekunden und der Hauptthread wird dabei nicht blockiert. Wenn einer der 4 Reader beendet ist, wird eine Zwischenzeit angezeigt.
  Private Async Function LeseDateiAsynchron() As Task
    Dim zeit = Date.Now
    Dim tasklist As New List(Of Task)
    tasklist.Add(Task.Run(AddressOf Leser1))
    tasklist.Add(Task.Run(AddressOf Leser2))
    tasklist.Add(Task.Run(AddressOf Leser3))
    tasklist.Add(Task.Run(AddressOf Leser4))
    While tasklist.Count > 0
      Dim tk = Await Task.WhenAny(tasklist)
      tasklist.Remove(tk)
      'Dim rg = Await tk '<- nur wenn auf einen Rückgabewert gewartet werden _
        soll.
      Me.ProgressBarFortschritt.Value += 20
      Me.LabelZeit.Text = String.Format("Zeit: {0:n1} Sek.", (Date.Now - _
        zeit).TotalSeconds)
    End While
    Me.ProgressBarFortschritt.Value = 100
  End Function
So kann z.B. der Inhalt einer Webseite asynchron gelesen werden.
Im Gegensatz zu synchronem Code, wird hier der Button wirklich deaktiviert und erst wieder aktiviert, wenn die Webseite gelesen wurde. Der Button reagiert zwischendurch auf keine Klicks und der Hauptthread wird nicht blockiert.
  Private Async Sub ButtonWeb_Click(sender As Object, e As EventArgs) Handles _
    ButtonWeb.Click
    Me.ButtonWeb.Enabled = False
    Dim inhalt = Await InhaltWebseite("...")
    '...
    Me.ButtonWeb.Enabled = True
  End Sub
 
  Private Async Function InhaltWebseite(url As String) As Task(Of String)
   Return Await New HttpClient().GetStringAsync(url)
  End Function
Man kann einzelne Tasks auch abbrechen oder mit Hilfe von Tor-Steuerung (ResetEvent) anhalten und fortsetzen.

Mit dem Threadpool hab ich bisher noch nicht direkt gearbeitet. Ich verwende fast nur Async oder BackGroundWorker und hatte damit noch nie Probleme.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Threadpool: Beendigung aller Threads feststellen 
Autor: Manfred X
Datum: 18.09.14 16:00

Hallo!

Deinen Vorschlag, die Abarbeitung der ThreadPool-Warteschlange
durch Ascync-Await zu überwachen, werde ich bei Gelegenheit
ausprobieren.






Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Threadpool: Beendigung aller Threads feststellen 
Autor: ModeratorDaveS (Moderator)
Datum: 18.09.14 19:05

Klar, es sind aber vielleicht ein paar Tipps dabei.

________
Alle Angaben ohne Gewähr. Keine Haftung für Vorschläge, Tipps oder sonstige Hilfe, falls es schiefgeht, nur Zeit verschwendet oder man sonst nicht zufrieden ist

Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Sie sind nicht angemeldet!
Um auf diesen Beitrag zu antworten oder neue Beiträge schreiben zu können, müssen Sie sich zunächst anmelden.

Einloggen  |  Neu registrieren

Funktionen:  Zum Thema  |  GesamtübersichtSuchen 

nach obenzurück
 
   

Copyright ©2000-2024 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel