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();
Related
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.
I want run a thread continuously. This thread would poll and check for card status. Here is a sample implementation:
static void Main(string[] args)
{
var _cancelationTokenSource = new CancellationTokenSource();
new Task(() => chkRequestTask(_cancelationTokenSource), _cancelationTokenSource.Token, TaskCreationOptions.LongRunning).Start();
while (true)
{
}
}
static bool chkRequestTask(CancellationTokenSource _cancellationTokenSource)
{
bool noRequest = false;
while (!_cancellationTokenSource.Token.IsCancellationRequested)
{
var RequestTask = Task.Factory.StartNew(() => noRequest = chkRequestTask(_cancellationTokenSource), _cancellationTokenSource.Token);
if (noRequest)
{
_cancellationTokenSource.Token.WaitHandle.WaitOne(15000);
Console.WriteLine("Waiting for 15Seconds");
}
else
{
Console.WriteLine("Checking the card");
}
}
return noRequest;
}
What I want to achieve here is chkRequestTask should be run on a separate thread. This would continously poll the status of the card. For this sample I'm simply doing : Console.WriteLine("Checking the card");.
Once it checks the status of the card it should sleep for 15secs for this sample only (in general it should check every 50ms, but for testing purposes I have kept 15secs).
But in the above sample it's not sleeping it's simply giving me Checking the card continuously. It's not sleeping at all for 15secs. What is wrong with this code ?
You're calling chkRequestTask recursively using Task.Factory.StartNew which you don't need at all.
It's not clear why you need to poll the status, better idea is to check any event or callback or WaitHandle provided by the card API you're talking about. That should keep you away from the pain.
If at all you believe polling is the only option you've left with, you can do it as follows.
static async Task ChkRequestTask(CancellationToken token)
{
while (true)
{
token.ThrowIfCancellationRequested();
Console.WriteLine("Checking the card");
bool status = PollTheCardForStatus();
if(!status)
break;
await Task.Delay(15 * 1000, token);//Adjust the delay as you wish
}
}
Else where in code, if possible await the call, If not then attach a continuation or use blocking task.Wait.
await ChkRequestTask(token);
This method doesn't need to return bool as you're returning from the method only when it is false, it is safe to assume the status is false when the Task returned from ChkRequestTask completes, which means poll returned false or the CancellationToken is cancelled, in which case you'll get TaskCanceledException
This is how I have done this. It seems to be working properly. As it's a background thread it would exit when the application exits. Could someone advise If this is the right way to do it.
private void Form1_Load(object sender, EventArgs e)
{
m_dev = DASK.Register_Card(DASK.PCI_7250, 0);
if (m_dev < 0)
{
MessageBox.Show("Register_Card error!");
}
FunctionToCall();
}
private void FunctionToCall()
{
short ret;
uint int_value;
var thread = new Thread(() =>
{
while (true)
{
ret = DASK.DI_ReadPort((ushort)m_dev, 0, out int_value);
if (ret < 0)
{
MessageBox.Show("D2K_DI_ReadPort error!");
return;
}
if (int_value > 0)
{
textBox2.Invoke(new UpdateText(DisplayText), Convert.ToInt32(int_value));
}
Thread.Sleep(500);
}
});
thread.Start();
thread.IsBackground = true;
}
private void DisplayText(int i)
{
textBox2.Text = i.ToString();
}
Hello guys I'm pretty new to the whole async stuff and it would be nice if you could give me some advice. I'm not really sure if my approach is OK.
Lets say I have a bus device that is reading data and it fires an event if a telegram is completed. Now I want to check each telegram for its length. If length == expectation -> OK if not try until is OK or timeout. But it want to check for length 1, 2 and 5 at the same time.
UPDATE:
OK I changed my example to an async approach but I still can't figure out how this should help me with my problem? OK on the plus side I don't have threads anymore that are blocked most of the time, but this wasn't my problem :(
So I try to explain in a different way. I want a async method that listens on the bus and returns the telegram that match the defined length
async Task<byte[]> GetTelegramAsync(int length, Timespan timeout)
I want to do something like this
Task<byte[]> t1 = GetTelegramAsync(1);
Task<byte[]> t2 = GetTelegramAsync(6);
Task<byte[]> t4 = GetTelegramAsync(4);
Task t4 = DoOtherStuffAsync();
DoStuff();
Task.WaitAll(AsyncRsp(t1), AsyncRsp(t2), AsyncRsp(t3), t4);
/* Output
Get telegram with length of 1
Get telegram with length of 6
Get telegram with length of 4
Start doing other async stuff
Sync stuff done...
Telegram found 0x00 0x01 0x02 0x03 0x04 0x05
Async stuff done...
Telegram found 0xFF
Telegram with length 4 not found
*/
Here is my first BusDevice class. A thread starts that listens on the bus, if a telegram is received an event fires.
class BusDeviceThread
{
private readonly Random _r = new Random();
private Thread _t;
public event EventHandler<TelegramReceivedArgs> TelegramReceived;
public void Connect()
{
_t = new Thread(FetchBusData)
{
Name = "FetchBusData",
Priority = ThreadPriority.Normal
};
_t.Start();
}
public void Close()
{
_t.Abort();
_t.Join();
}
private void FetchBusData()
{
while (true)
{
Thread.Sleep(_r.Next(100, 1000));
var buffer = new byte[_r.Next(1, 10)];
_r.NextBytes(buffer);
OnTelegramReceived(new TelegramReceivedArgs(buffer));
}
}
private void OnTelegramReceived(TelegramReceivedArgs e)
{
var handler = TelegramReceived;
if (handler != null) handler(this, e);
}
}
And here is the changed BusDevice class utilizing async await.
class BusDeviceAsync
{
private readonly Random _r = new Random();
public event EventHandler<TelegramReceivedArgs> TelegramReceived;
public async Task Connect(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
var telegram = await FetchBusData();
OnTelegramReceived(new TelegramReceivedArgs(telegram.ToArray()));
}
}
private async Task<IEnumerable<byte>> FetchBusData()
{
await Task.Delay(_r.Next(100, 1000));
var buffer = new byte[_r.Next(1, 10)];
_r.NextBytes(buffer);
return buffer;
}
private void OnTelegramReceived(TelegramReceivedArgs e)
{
var handler = TelegramReceived;
if (handler != null) handler(this, e);
}
}
Like I said it doesn't help me with my problem, the
async Task<byte[]> GetTelegramAsync(int length, Timespan timeout)
implementation stays the same or do I miss a point here?
byte[] GetTelegram(int length, TimeSpan timeout)
{
byte[] telegram = null;
using (var resetEvent = new AutoResetEvent(false))
{
EventHandler<TelegramReceivedArgs> handler = (sender, e) =>
{
var t = e.Telegram;
if (Check(t, length))
{
telegram = t;
resetEvent.Set();
}
};
_d.TelegramReceived += handler;
resetEvent.WaitOne(timeout.Milliseconds);
_d.TelegramReceived -= handler;
}
return telegram ?? new byte[0];
}
async Task<byte[]> GetTelegramAsync(int length, TimeSpan timeout)
{
return await Task.Run(() => GetTelegram(length, timeout));
}
I updated my example, but I can't figure out the difference regarding
my problem. Well I certainly have fixed the blocked thread "problem".
This is not exactly what I meant, you're still using the pull model for your data (now with help of Task.Delay), not the push model (where the notification is coming asynchronously from the bus driver, as shown here).
Anyway, I think the following implementation might be what you're looking for. Note it doesn't explicitly use threads at all, beside for async I/O bus read simulation. Substitute the real device APM API for readBus:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
public class TelegramEventArg: EventArgs
{
public byte[] Data { get; set; }
}
public EventHandler<TelegramEventArg> TelegramEvent = delegate { };
async Task<byte[]> ReadTelegramAsync(int size, CancellationToken token)
{
var tcs = new TaskCompletionSource<byte[]>();
EventHandler<TelegramEventArg> handler = null;
bool subscribed = false;
handler = (s, e) =>
{
if (e.Data.Length == size)
{
this.TelegramEvent -= handler;
subscribed = false;
tcs.TrySetResult(e.Data);
}
};
this.TelegramEvent += handler;
try
{
subscribed = true;
using (token.Register(() => tcs.TrySetCanceled()))
{
await tcs.Task.ConfigureAwait(false);
return tcs.Task.Result;
}
}
finally
{
if (subscribed)
this.TelegramEvent -= handler;
}
}
async Task ReadBusAsync(CancellationToken token)
{
while (true)
{
// get data from the bus
var data = await Task.Factory.FromAsync(
(asyncCallback, asyncState) =>
readBus.BeginInvoke(asyncCallback, asyncState),
(asyncResult) =>
readBus.EndInvoke(asyncResult),
state: null).ConfigureAwait(false);
token.ThrowIfCancellationRequested();
this.TelegramEvent(this, new TelegramEventArg { Data = data });
}
}
// simulate the async bus driver with BeginXXX/EndXXX APM API
static readonly Func<byte[]> readBus = () =>
{
var random = new Random(Environment.TickCount);
Thread.Sleep(random.Next(1, 500));
var data = new byte[random.Next(1, 5)];
Console.WriteLine("A bus message of {0} bytes", data.Length);
return data;
};
static void Main(string[] args)
{
try
{
var program = new Program();
var cts = new CancellationTokenSource(Timeout.Infinite); // cancel in 10s
var task1 = program.ReadTelegramAsync(1, cts.Token);
var task2 = program.ReadTelegramAsync(2, cts.Token);
var task3 = program.ReadTelegramAsync(3, cts.Token);
var busTask = program.ReadBusAsync(cts.Token);
Task.WaitAll(task1, task2, task3);
Console.WriteLine("All telegrams received");
cts.Cancel(); // stop ReadBusAsync
}
catch (Exception ex)
{
while (ex is AggregateException)
ex = ex.InnerException;
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
}
Also, this scenario appears to be an ideal candidate for implementation using Reactive Extensions (Rx). As time allows, I'll show how to do that.
I am opening n concurrent threads in my function:
List<string> _files = new List<string>();
public void Start()
{
CancellationTokenSource _tokenSource = new CancellationTokenSource();
var token = _tokenSource.Token;
Task.Factory.StartNew(() =>
{
try
{
Parallel.ForEach(_files,
new ParallelOptions
{
MaxDegreeOfParallelism = 5 //limit number of parallel threads
},
file =>
{
if (token.IsCancellationRequested)
return;
//do work...
});
}
catch (Exception)
{ }
}, _tokenSource.Token).ContinueWith(
t =>
{
//finish...
}
, TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
);
}
there is a way to know while this function still processing that 1 file finish ? i am now talking about ContinueWith which this is the case after all my list has finished.
Not sure I perfectly understand your issue but you could use some standard notification through a method:
public void Start()
{
CancellationTokenSource _tokenSource = new CancellationTokenSource();
var token = _tokenSource.Token;
Task.Factory.StartNew(() =>
{
try
{
Parallel.ForEach(_files,
new ParallelOptions
{
MaxDegreeOfParallelism = 5 //limit number of parallel threads
},
file =>
{
if (token.IsCancellationRequested)
return;
//do work...
OnDone(file);
});
}
catch (Exception)
{ }
}, _tokenSource.Token).ContinueWith(
t =>
{
//finish...
}
, TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
);
}
public void OnDone(string fileName)
{
// Update the UI, assuming you're using WPF
someUIComponent.Dispatcher.BeginInvoke(...)
}
You may need additional locks if you update some shared state, but to only update the UI (e.g. a row in a datagrid or an element in a list) should be fine because the synchronization is enforced by the dispatcher invocation.
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