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();
}
Related
I have a button click event handler in which I need to have 3 sec delay to make some flag true ..so it takes time to completely execute the function now meantime if the user click on the button again then this is making flag true for second click also...so I want to cancel the first click event as soon as I receive another click request.
This is my code :
private async void ClickEventHandler(ClickEvent obj)
{
int indexOfSelectedItem = this.List.IndexOf(this.List.FirstOrDefault(x => Convert.ToDouble(x.Value) == obj.Value));
if (indexOfSelectedItem > -1)
{
for (int i = 0; i < indexOfSelectedItem; i++)
{
var item = this.List.ElementAtOrDefault(0);
this.List.RemoveAt(0);
this.List.Add(item);
}
this.IsScrollEnabled = false;
await Task.Delay(3000);
this.IsScrollEnabled = true;
}
}
Yes I need to cancel the execution of the first method and call the method again ..so that it will wait for 3 sec after clicking it on second time
A simple example with a cancellation token:
private CancellationTokenSource tokenSource = new();
private async void ClickEventHandler(ClickEvent obj)
{
// Since this method is called from the clicker,
// it always starts on the main thread. Therefore,
// there is no need for additional Thread-Safe.
tokenSource.Cancel();
tokenSource = new();
CancellationToken token = tokenSource.Token;
int indexOfSelectedItem = this.List.IndexOf(this.List.FirstOrDefault(x => Convert.ToDouble(x.Value) == obj.Value));
if (indexOfSelectedItem > -1)
{
for (int i = 0; i < indexOfSelectedItem; i++)
{
var item = this.List.ElementAtOrDefault(0);
this.List.RemoveAt(0);
this.List.Add(item);
}
this.IsScrollEnabled = false;
try
{
// If the cancellation is during the Delay, then an exception will be exited.
await Task.Delay(3000, token);
this.IsScrollEnabled = true;
}
catch (Exception)
{
// Here, if necessary, actions in case the method is canceled.
}
}
}
P.S. In the example, the token is checked only in the Delay(...) method. If you need to check somewhere else, then insert a call to the method token.ThrowIfCancellationRequested(); into this place.
you could change a variable when the button gets clicked and change it back after it is done and then add an if statement checking the variable
As like xceing said , you can have a variable to check if already clicked and yet to complete the process.
Here is a sample
//keep a variable to check already clicked and yet to complete the action
bool clickEventInProgress = false;
private async void ClickEventHandler(ClickEvent obj)
{
//check it before start processing click action
if (!clickEventInProgress)
{
clickEventInProgress = true;
int indexOfSelectedItem = this.List.IndexOf(this.List.FirstOrDefault(x => Convert.ToDouble(x.Value) == obj.Value));
if (indexOfSelectedItem > -1)
{
for (int i = 0; i < indexOfSelectedItem; i++)
{
var item = this.List.ElementAtOrDefault(0);
this.List.RemoveAt(0);
this.List.Add(item);
}
this.IsScrollEnabled = false;
await Task.Delay(3000);
this.IsScrollEnabled = true;
}
clickEventInProgress = false;
}
}
you can make the variable false, one the process completed . So that next click operation will work fine.
It's not clear what exactly you are doing. A general solution could execute the cancellable task using Task.Run and then cancel it using a CancellationTokenSource. It's important to pass the associated CancellationToken to the Task API (and any asynchronous API that supports cancellation in general) too in order to enable full cancellation support e.g. cancellation of Task.Delay:
MainWindow.xaml
<Window>
<Button Content="Go!"
Click="OnClick" />
</Window>
MainWindow.xaml.cs
partial class MainWindow : Window
{
private CancellationTokenSource CancellationTokenSource { get; set; }
private SemaphoreSlim Semaphore { get; } = new SemaphoreSlim(1, 1);
public MainWindow() => InitializeComponent();
private async void OnClick(object sender, RoutedEventArgs e)
{
// If there is nothing to cancel, the reference is NULL
this.CancellationTokenSource?.Cancel();
// Wait for the previous operation to be cancelled.
// If there is nothing to cancel the SemaphoreSlim has a free slot
// and the execution continues.
await this.Semaphore.WaitAsync();
try
{
using (this.CancellationTokenSource = new CancellationTokenSource())
{
await RunCancellableOperationAsync(this.CancellationTokenSource.Token);
}
}
catch (OperationCanceledException)
{
// Invalidate disposed object to make it unusable
this.CancellationTokenSource = null;
}
finally // Cancellation completed
{
this.Semaphore.Release();
}
}
private async Task RunCancellableOperationAsync(CancellationToken cancellationToken)
{
// Execute blocking code concurrently to enable cancellation
await Task.Run(() =>
{
for (int index = 0; index < 1000; index++)
{
// Abort the iteration if requested
cancellationToken.ThrowIfCancellationRequested();
// Simulate do something
Thread.Sleep(5000);
}
}, cancellationToken);
// Support cancellation of the delay
await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken);
}
}
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();
I am a newbie with C#. I am trying to get a task to run in parallel to a stored procedure execution. So for example - I have a stored procedure which in this instance will just be running WAITFOR DELAY '00:00:10'. During that ten seconds a label will be populated with text which will have full stops added and then remove as you would see in a loading screen.
Disabling Replication.
Disabling Replication..
Disabling Replication...
Once the proc is completed it will break out of the while loop. This is being handled by a boolean value. So _IsRunning = false, run stored procedure then set IsRunning = true. The code works exactly as I would want it to if I just use Thread.Sleep(1000), which I used for test purposes, instead of a stored procedure.
Can someone tell me why this will not work when using the stored procedure? It just gets stuck on the while loop and constantly says Disabling Replication with the loading full stops.
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AsynchronousCoding
{
public partial class Form1 : Form
{
private DataAccess _access = new DataAccess();
public Form1()
{
InitializeComponent();
}
private async Task LoadRapport()
{
await DisableReplication();
}
private async Task DisableReplication()
{
Task.Factory.StartNew(TestMethod);
await Task.Factory.StartNew(() => ShowProgressText("Disabling Replication"));
}
private bool _IsRunning;
private void TestMethod()
{
_isRunning= false;
//Thread.Sleep(10000);
_access.Rapport_ReplicationSetting();
_isRunning= true;
}
private void ShowProgressText(string txt)
{
var count = 0;
var logText = new StringBuilder();
logText.Append(txt);
var baseLen = logText.Length;
while (!_isRunning)
{
Thread.Sleep(250);
if (count >= 3)
{
logText.Remove(baseLen, count);
count = 0;
}
logText.Append(".");
count++;
BeginInvoke(new Action(() => { UpdateProgressText(logText.ToString()); }));
}
BeginInvoke(new Action(() => { UpdateProgressText(txt + " - Complete"); }));
Thread.Sleep(2000);
}
private void UpdateProgressText(string txt)
{
lblProgress.Text = txt;
}
private void button1_Click(object sender, EventArgs e)
{
LoadRapport();
}
}
}
Consider this simple example with CancellationToken usage. I don't suggest bool, it's not Thread-safe.
private async void button1_Click(object sender, EventArgs e)
{
IProgress<string> progress = new Progress<string>(s => lblProgress.Text = s);
using (CancellationTokenSource cts = new CancellationTokenSource());
{
Task animationTask = ProgressAnimationAsync(progress, cts.Token);
await DoSomeJobAsync();
// await Task.Run(() => DoSomeHeavyJob()); // uncomment for test
cts.Cancel();
await animationTask;
}
}
private async Task ProgressAnimationAsync(IProgress progress, CancellationToken token)
{
int i = 1;
while (!token.IsCancellationRequested)
{
progress.Report("Loading" + new string("." , i));
i = i == 3 ? 1 : i + 1;
await Task.Delay(250);
}
}
// as I/O-bound operation
private async Task DoSomeJobAsync()
{
await Task.Delay(10000);
}
// as CPU-bound operation
private void DoSomeHeavyJob()
{
Thread.Sleep(10000);
}
There's two different methods, you can test both.
Note: it's safe to use lblProgress.Text directly here, without IProgress synchronized callback. It's given here just for example. Create new Progress in UI Thread and you may call .Report() from any other Thread safely without Invoke or BeginInvoke.
You can learn more about X-bound operations here.
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();
I have this issue. I want to make calls to various numbers through Skype. In order for this to work I have to place a call and then wait for this call to complete (it is dropped upon receiving a ringing tone) before I make another call.
The problem is that although I try to do it asynchronously and wait for the function to return I get an error indicating that the next call begins before the first completes. Here is the code:
class Program
{
static Skype skype = new Skype();
static String[] numbers = new String[] { "phonenumber1", "phonenumber2" };
public delegate void TCall(Call pCall, TCallStatus Status);
static void Main(string[] args)
{
((_ISkypeEvents_Event)skype).AttachmentStatus += OnAttachmentStatus;
skype.Attach(8);
Console.ReadLine();
}
static void OnAttachmentStatus(TAttachmentStatus status)
{
Console.WriteLine("attacment: " + skype.Convert.AttachmentStatusToText(status));
// only after this apiAttachSuccess can we do much anything
if (status == TAttachmentStatus.apiAttachSuccess)
{
foreach (string number in numbers)
{
Call pCall = skype.PlaceCall(number);
TCall theCall = OnCallStatus;
IAsyncResult ar = theCall.BeginInvoke(pCall, pCall.Status, null, null);
theCall.EndInvoke(ar);
while (!ar.IsCompleted)
{
Thread.Sleep(200);
}
Console.WriteLine("Next Call Please");
}
}
}
static void OnCallStatus(Call pCall, TCallStatus Status)
{
//Thread.Sleep(2000);
var sw = Stopwatch.StartNew();
while (sw.ElapsedMilliseconds<=5000)
{
if (pCall.Status == TCallStatus.clsRinging)
{
Console.WriteLine("Ringing");
break;
}
}
return;
}
}
What am I doing wrong?
I think you're calling EndInvoke too early. Trying moving it after the while loop.
Alternatively, you can use a wait handle like this
IAsyncResult ar = theCall.BeginInvoke(pCall, pCall.Status, null, null);
ar.AsyncWaitHandle.WaitOne(); //Blocks until complete
theCall.EndInvoke(ar);