First: What I want to do?
I want to run multiple jobs on one thread, for example, I want to make a thread for calculations and always run methods inside of that.
Get a pointer like SynchronizationContext.Current or Thread.CurrentThread to access current job working.
3.A Cross-Platform way like Net Standard.
Second: Example-1 (CrossPlatform-Working) My example not working, because Post and Send method in SynchronizationContext don't work
class Program
{
static void Main(string[] args)
{
SynchronizationContext contextThread1 = null;
SynchronizationContext contextThread2 = null;
Thread thread1, thread2 = null;
thread1 = new Thread(() =>
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
contextThread1 = SynchronizationContext.Current;
while (true)
{
Thread.Sleep(1000);
if (contextThread2 != null)
{
contextThread2.Post((state) =>
{
//Thread.CurrentThread == thread2 always false because the method is not runnig from thread 2
Console.WriteLine("call a method from thread 1 for thread 2 :" + (Thread.CurrentThread == thread2));
}, null);
}
}
});
thread1.IsBackground = true;
thread1.Start();
thread2 = new Thread(() =>
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
contextThread2 = SynchronizationContext.Current;
while (true)
{
Thread.Sleep(1000);
if (contextThread1 != null)
{
contextThread1.Post((state) =>
{
//Thread.CurrentThread == thread1 always false because the method is not runnig from thread 1
Console.WriteLine("call a method from thread 2 for thread 1 :"+(Thread.CurrentThread == thread1));
}, null);
}
}
});
thread2.IsBackground = true;
thread2.Start();
Console.ReadKey();
}
}
Example-2: (No Cross PLatform because Windowsbase.dll): this example works fine but this is not cross platform.
class Program
{
static void Main(string[] args)
{
Dispatcher contextThread1 = null;
Dispatcher contextThread2 = null;
Thread thread1, thread2 = null;
thread1 = new Thread(() =>
{
contextThread1 = Dispatcher.CurrentDispatcher;
Dispatcher.Run();
});
thread1.IsBackground = true;
thread1.Start();
thread2 = new Thread(() =>
{
contextThread2 = Dispatcher.CurrentDispatcher;
Dispatcher.Run();
});
thread2.IsBackground = true;
thread2.Start();
while (true)
{
Thread.Sleep(1000);
if (contextThread2 != null)
{
contextThread2.Invoke(new Action(() =>
{
//Thread.CurrentThread == thread2 always false because the method is not runnig from thread 2
Console.WriteLine("call a method from thread 1 for thread 2 :" + (Thread.CurrentThread == thread2));
}));
}
if (contextThread1 != null)
{
contextThread1.Invoke(new Action(() =>
{
Console.WriteLine("call a method from thread 2 for thread 1 :" + (Thread.CurrentThread == thread1));
}));
}
}
Console.ReadKey();
}
}
You should always use a tool these days to make your life easier where possible. In this case you should use Microsoft's Reactive Framework. Just NuGet "System.Reactive" and add using System.Reactive.Linq;.
Then you can do this:
void Main()
{
var thread1 = new EventLoopScheduler();
var thread2 = new EventLoopScheduler();
Action action = () => Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
action();
thread1.Schedule(action);
Thread.Sleep(1000);
thread2.Schedule(action);
Thread.Sleep(1000);
thread2.Schedule(() =>
{
action();
thread1.Schedule(action);
});
Thread.Sleep(1000);
action();
}
The kind of output I get is:
11
12
14
14
12
11
If you follow along with the code you can see it is correctly scheduling to each thread.
When you want to shut down just call .Dispose() on each EventLoopScheduler.
Related
I'm writing a simple producer/consumer application, but I'm noticing a really strange behaviour..This is the code:
private Thread _timelineThread = null;
private BufferBlock<RtpPacket> _queue = null;
private AutoResetEvent _stopping = new AutoResetEvent(false);
static void Main(string[] args)
{
// Start consumer thread
Consume();
// Produce
var t = new Thread(() =>
{
while (true)
{
var packet = RtpPacket.GetNext();
_queue.Post(packet);
Thread.Sleep(70);
}
}
t.Join();
}
static void Consume()
{
_timelineThread = new Thread(async () =>
{
while (_stopping.WaitOne(0) == false)
{
// Start consuming...
while (await _queue.OutputAvailableAsync())
{
var packet = await _queue.ReceiveAsync();
// Some processing...
}
}
});
_timelineThread.Start();
}
This is intended to be an infinite loop (until I route the _stopping signal). But, when _timelineThread hits the first await _queue.OutputAvailableAsync(), the thread changes state to 'Stopped'. There is something wrong that I'm not considering ?
If I change the Consume() function to this:
static void Consume()
{
_timelineThread = new Thread(() =>
{
while (_stopping.WaitOne(0) == false)
{
// Start consuming...
while (_queue.OutputAvailableAsync().GetAwaiter().GetResult())
{
var packet = _queue.ReceiveAsync().GetAwaiter().GetResult();
// Some processing...
}
}
});
_timelineThread.Start();
}
the thread runs without any problem..but the code is almost identical to the previous one..
EDIT: after one hour also this 'hack' doesn't seems to work..thread is 'Running' but I don't receive any data from the queue..
The Thread constructor does not understand async delegates. You can read about this here:
Is it OK to use "async" with a ThreadStart method?
Async thread body loop, It just works, but how?
My suggestion is to use a synchronous BlockingCollection<RtpPacket> instead of the BufferBlock<RtpPacket>, and consume it by enumerating the GetConsumingEnumerable method:
var _queue = new BlockingCollection<RtpPacket>();
var producer = new Thread(() =>
{
while (true)
{
var packet = RtpPacket.GetNext();
if (packet == null) { _queue.CompleteAdding(); break; }
_queue.Add(packet);
Thread.Sleep(70);
}
});
var consumer = new Thread(() =>
{
foreach (var packet in _queue.GetConsumingEnumerable())
{
// Some processing...
}
});
producer.Start();
consumer.Start();
producer.Join();
consumer.Join();
im developing an app for android via c#(xamarin.visual studio) , the problem is that i have some task to do that running in other threads , and when it should update the layout it should call Activity.RunOnUIThread , everything it's working well but the thread dont wait this method to finnish and continue executing the rest withuout waiting.
The question is : How to wait for RunOnUIThread to finish and after that continue executing rest of the commands of the task. ?
public void start(int threadCounter)
{
for (int i = 0; i < threadCounter; i++)
{
Thread thread1 = new Thread(new ThreadStart(RunScanTcp));
thread1.Start();
}
}
public void RunScanTcp()
{
int port;
//while there are more ports to scan
while ((port = portList.NextPort()) != -1)
{
count = port;
Thread.Sleep(1000); //lets be a good citizen to the cpu
Console.WriteLine("Current Port Count : " + count.ToString());
try
{
Connect(host, port, tcpTimeout);
}
catch
{
continue;
}
Activity.RunOnUiThread(() =>
{
mdata.Add(new data() { titulli = "Port : " + port, sekuenca = "Sequence : ", ttl = "Connection Sucessfull !", madhesia = "", koha = "Time : " });
mAdapter.NotifyItemInserted(mdata.Count() - 1);
if (ndaluar == false)
{
mRecyclerView.ScrollToPosition(mdata.Count() - 1);
}
}); // in that point i want to wait this to finish and than continue below...
Console.WriteLine("TCP Port {0} is open ", port);
}
First of all you should avoid creating new Threads.
In you case you must use ThreadPool.QueueUserWorkItem to enqueue the CPU bound operation.
Then you could use a ManualResetEventSlim or TaskCompletionSource to synchronize the the UI thread and the Worker Thread.
Example:
// mre is used to block and release threads manually. It is
// created in the unsignaled state.
ManualResetEventSlim mre = new ManualResetEventSlim(false);
RunOnUiThread(() =>
{
// Update UI here.
// Release Manual reset event.
mre.Set();
});
// Wait until UI operations end.
mre.Wait();
In your specific case:
for (int i = 0; i < threadCounter; i++)
{
ThreadPool.QueueUserWorkItem(RunScanTcp);
}
private void RunScanTcp(object stateInfo)
{
// Do CPU bound operation here.
var a = 100;
while (--a != 0)
{
// mre is used to block and release threads manually. It is
// created in the unsignaled state.
ManualResetEventSlim mre = new ManualResetEventSlim(false);
Activity.RunOnUiThread(() =>
{
// Update UI here.
// Release Manual reset event.
mre.Set();
});
// Wait until UI operation ends.
mre.WaitOne();
}
}
If you prefer to use TaskCompletionSource you could use an alternative approach:
private async void RunScanTcp(object stateInfo)
{
// Do CPU bound operation here.
var a = 100;
while (--a != 0)
{
// using TaskCompletionSource
var tcs = new TaskCompletionSource<bool>();
RunOnUiThread(() =>
{
// Update UI here.
// Set result
tcs.TrySetResult(true);
});
// Wait until UI operationds.
tcs.Task.Wait();
}
}
You could use Monitor.Wait and Monitor.Pulse with a shared myLock object to wait for the UI execution.
Activity.RunOnUiThread(() =>
{
mdata.Add(new data() { titulli = "Port : " + port, sekuenca = "Sequence : ", ttl = "Connection Sucessfull !", madhesia = "", koha = "Time : " });
mAdapter.NotifyItemInserted(mdata.Count() - 1);
if (ndaluar == false)
{
mRecyclerView.ScrollToPosition(mdata.Count() - 1);
}
lock(myLock) Monitor.Pulse(myLock)
});
lock(myLock) Monitor.Wait(myLock)
Console.WriteLine("TCP Port {0} is open ", port);
For those interested in an async/await solution, there is Stephen Cleary's AsyncManualResetEvent, e.g.:
var mre = new AsyncManualResetEvent();
this.context.RunOnUiThread(() =>
{
// Do awesome UI stuff
mre.Set();
});
await mre.WaitAsync();
Background:
In C# WinForm, I use several Threads like this
private Thread Thread1;
Thread1 = new Thread(new ThreadStart(DoSomething));
Thread1.Start();
And I want to set a timer to Stop/Kill the Thread1 every hour, and restart a new Thread1 like this:
Abort/Kill Thread1;
Thread1 = new Thread(new ThreadStart(DoSomething));
Thread1.Start();
So How to kill the thread1 and restart a new one without Restart my Winform?
Thank you kindly for your reply. I much appreciated it
You can do so by having a while loop in DoSomething that continues based on a volatile bool. Please see Groo's answer here:
Restarting a thread in .NET (using C#)
Here is a sample.
private void button1_Click(object sender, EventArgs e) {
var i = 0;
Action DoSomething = () => {
while (true) {
(++i).ToString();
Thread.Sleep(100);
}
};
Thread Thread1;
Thread1 = new Thread(new ThreadStart(DoSomething));
Thread1.Start();
Thread.Sleep(1000);
Text = i.ToString();
Thread1.Abort();
Thread1 = new Thread(new ThreadStart(DoSomething));
Thread1.Start();
}
I don't recommend Thread.Abort method.
When possible, design the thread what can stop safety. And use Join method.
private void button2_Click(object sender, EventArgs e) {
// the flag, to stop the thread outside.
var needStop = false;
var i = 0;
Action DoSomething = () => {
while (!needStop) {
(++i).ToString();
Thread.Sleep(100);
}
};
Thread Thread1;
Thread1 = new Thread(new ThreadStart(DoSomething));
Thread1.Start();
Thread.Sleep(1000);
Text = i.ToString();
// change flag to stop.
needStop = true;
// wait until thread stop.
Thread1.Join();
// start new thread.
Thread1 = new Thread(new ThreadStart(DoSomething));
Thread1.Start();
// needStop = true;
// Thread1.Join();
}
I am starting a thread and updating form element but following code is making form unresposive please suggest what I am doing wrong here.
private void StartTimer()
{
Thread t = new Thread(Updates);
t.IsBackground = true;
t.Start();
}
private void Updates()
{
try
{
while (true)
{
this.Invoke((MethodInvoker)delegate
{
lblTotalImages.Text = AppHelper.GetTotalCount(textBox1.Text).ToString();
if (sitename != null)
{
lblTotalPosted.Text = AppHelper.GetPostedCount(sitename).ToString();
// Application.DoEvents();
}
});
Thread.Sleep(1000);
}
}
catch (Exception ex)
{
}
}
Edit-------
Thanks #Servy for introducing Task Parallel Library i have never used it here is solution i come up with i used timer and task factory
ya for .net 4 without library extension and vs 2010 i have this working perfectly
enter code here private void timer1_Tick(object sender, EventArgs e)
{
Task.Factory.StartNew(() => AppHelper.GetTotalCount(textBox1.Text)).ContinueWith(t => lblTotalImages.Text = t.Result.ToString(), TaskScheduler.FromCurrentSynchronizationContext());
if (sitename != null)
{
Task.Factory.StartNew(() => AppHelper.GetPostedCount(sitename)).ContinueWith(t => lblTotalPosted.Text = t.Result.ToString(), TaskScheduler.FromCurrentSynchronizationContext());
}
}
You are doing some sort of long running non-UI operation inside of the call to Invoke, which means it's being done in the UI thread. You should strive to only be updating the UI in the UI thread; ensure that any long running non-UI code is outside of any invocations to the UI thread.
The use of await also allows this solution to be written in a much simpler and more effective manor:
public async void StartTimer()
{
while (true)
{
string text = textBox1.Text;
lblTotalImages.Text = await Task.Run(() =>
AppHelper.GetTotalCount(text).ToString());
if (sitename != null)
{
lblTotalPosted.Text = await Task.Run(() =>
AppHelper.GetPostedCount(sitename).ToString());
}
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
I am not using any thread pool. Just creating ThreadArray.The for loop creats the thread but same time main thread continues.... How can I apply wait on main thread until all threads created by for loop not get completed.
Code:
public List<DirInfo> ScanDir()
{
for (int i = 0; i < 5; i++)
{
threadArray[i] = new Thread(delegate()
{
StartScanning(paths);
}
);
threadArray[i].Start();
}
....
List<DirInfo> listInfo = new List<DirInfo>();
...
...
....
return listInfo
}
Code:
public List<ServerDataInformation> ScanParallel()
{
var appConfigData = ReadAppConfig();
if (appConfigData == null)
{
EventPublisher.NotifyApplication("Error in appconfig File");
return null;
}
int pathCount = appConfigData.Length;
string serverPath;
string serverName;
var waitHandles = new WaitHandle[pathCount];
Thread[] threadArray = new Thread[pathCount];
for (int i = 0; i < pathCount; i++)
{
// waitHandles[i] = new AutoResetEvent(false);
var handle = new EventWaitHandle(false, EventResetMode.ManualReset);
serverPath = appConfigData[i].Split(',').First();
serverName = appConfigData[i].Split(',').Last();
var threadSplit = new Thread(() =>
{
ScanProcess(serverPath, serverName); --------->> not executing as many times as I increment
handle.Set();
});
waitHandles[i] = handle;
threadSplit.Start();
}
//if (WaitHandle.WaitAll(waitHandles))
//{
// return serverDataInfoList;
// // EventPublisher.NotifyApplication("timeout!!");
//}
return serverDataInfoList;
}
Here 4 is the lenght of pathCount but
ScanProcess(serverPath, serverName);
is not executing 4 time with different values. It is executing 4 times but with same vaues
You could use wait handles:
var waitHandles = new ManualResetEvent[10];
for (int i = 0; i < 10; i++)
{
waitHandles[i] = new ManualResetEvent(false);
new Thread(waitHandle =>
{
// TODO: Do some processing...
// signal the corresponding wait handle
// ideally wrap the processing in a try/finally
// to ensure that the handle has been signaled
(waitHandle as ManualResetEvent).Set();
}).Start(waitHandles[i]);
}
// wait for all handles to be signaled => this will block the main
// thread until all the handles have been signaled (calling .Set on them)
// which would indicate that the background threads have finished
// We also define a 30s timeout to avoid blocking forever
if (!WaitHandle.WaitAll(waitHandles, TimeSpan.FromSeconds(30)))
{
// timeout
}
Have you tried the .Net 4 Task Parallel Library
MSDN Task Parallel Library
Task[] tasks = new Task[3]
{
Task.Factory.StartNew(() => MethodA()),
Task.Factory.StartNew(() => MethodB()),
Task.Factory.StartNew(() => MethodC())
};
//Block until all tasks complete.
Task.WaitAll(tasks);
// Continue on this thread...
Associate each thread with a waithandle, then use WaitHandle.WaitAll.If you start thread by async delegate call instead of a new thread object, it will give you the async result as waithandle.
for(int i = 0;i<10;i++)
{
thread = new Thread(new ThreadStart(Get_CR_Information));
thread.IsBackground = true;
thread.Start();
WaitHandle[] AWait = new WaitHandle[] { new AutoResetEvent(false) };
while ( thread.IsAlive)
{
WaitHandle.WaitAny(AWait, 50, false);
System.Windows.Forms.Application.DoEvents();
}
}
try this it will work fine...
Try using CountdownEvent synchronization primitive, Below link contains an example.
https://msdn.microsoft.com/en-us/library/dd997365(v=vs.110).aspx