How to cancel a task or terminate the task execution instantly? - c#-4.0

I have a windows service developed in C#. On it's Start method I have a initialization such as:
Task _backgroundTask = null;
CancellationTokenSource _backgroundCancellationSource = null;
protected override void OnStart(string[] args)
{
......
_backgroundCancellationSource = new CancellationTokenSource();
CancellationToken token = backgroundCancellationSource.Token;
_backgroundTask = new Task(() => BackgroundFoldersProcessing(token), token, TaskCreationOptions.LongRunning);
.......
}
Now the method BackgroundFoldersProcessing looks like this:
void BackgroundFoldersProcessing(CancellationToken token)
{
while (true)
{
try
{
if (token.IsCancellationRequested)
{
return;
}
DoSomeWork()
}
catch (Exception ex)
{
.........
}
}
}
Now, the Stop method is as follows:
protected override void OnStop()
{
.................
_backgroundCancellationSource.Cancel();
_backgroundTask.Wait();
_backgroundCancellationSource.Dispose();
_backgroundTask.Dispose();
_backgroundTask = null;
_backgroundCancellationSource = null;
.................
}
Now the problem is when I try to stop the service in a middle of processing, the Wait method of _backgroundTask would not stop the service until and unless the DoSomeWork() method inside the BackgroundFoldersProcessing gets completed, the Windows Service would not stop.
Is there any way, though which I can stop the service and the execution of _backgroundTask would be terminated, even though the DoSomeWork() method gets completed/executed or not? I have also tried token.ThrowIfCancellationRequested() in BackgroundFoldersProcessing method, but that also did not worked. I want that whenever I try to Stop the service from Service Control Manager (SCM), the service should be stopped immediately and the __backgroundTask should stop executing the BackgroundFoldersProcessing method and be terminated as well. How can I achieve this?

You can try use ThreadAbortException:
defining the thread:
ThreadStart threadDelegate = new ThreadStart(BackgroundFoldersProcessing);
Thread thread_ = new Thread(threadDelegate);
thread_.Start();
Add catch to BackgroundFoldersProcessing
catch (ThreadAbortException e)
{
return;
}
and when you want to shut it down use:
thread_.Abort();
thread_.Join();
Then when Abort() will be called ThreadAbortException will be thrown.

Related

javamail idle stops triggering messagesAdded after a while, thread locked

I'm developing an android app that receives and processes mail messages. The app must be connected to an IMAP server and keep the connection alive, so it can see and process new mail messages instantly (mails contains json data from a mail api server). The app have two modes, manual and live connection. Here is some of my code:
class Idler {
Thread th;
volatile Boolean isIdling=false;
boolean shouldsync=false;//we need to see if we have unseen mails
Object idleLock;
Handler handler=new Handler();
IMAPFolder inbox;
public boolean keppAliveConnection;//keep alive connection, or manual mode
//This thread should keep the idle connection alive, or in case it's set to manual mode (keppAliveConnection=false) get new mail.
Thread refreshThread;
synchronized void refresh()
{
if(isIdling)//if already idling, just keep connection alive
{
refreshThread =new Thread(new Runnable() {
#Override
public void run() {
try {
inbox.doCommand(new IMAPFolder.ProtocolCommand() {
#Override
public Object doCommand(IMAPProtocol protocol) throws ProtocolException {
//Why not noop?
//any call to IMAPFolder.doCommand() will trigger waitIfIdle, this
//issues a "DONE" command and waits for idle to return(ideally with a DONE server response).
// So... I think NOOP is unnecessary
//protocol.simpleCommand("NOOP",null); I'm not issuing noop due to what I said ^
//PD: if connection was broken, then server response will never arrive, and idle will keep running forever
//without triggering messagesAdded event any more :'( I see any other explanation to this phenomenon
return null;
}
});
} catch (MessagingException e) {
e.printStackTrace();
}
}
},"SyncThread");
refreshThread.start();
}
else
{
getNewMail();//If manual mode keppAliveConnection=false) get the new mail
}
}
public Idler()
{
th=new Thread(new Runnable() {
#SuppressWarnings("InfiniteLoopStatement")
#Override
public void run() {
while (true)
{
try {
if(refreshThread !=null && refreshThread.isAlive())
refreshThread.interrupt();//if the refresher thread is active: interrupt. I thing this is not necessary at this point, but not shure
initIMAP();//initializes imap store
try {
shouldsync=connectIMAP()||shouldsync;//if was disconnected or ordered to sync: needs to sync
}
catch (Exception e)
{
Thread.sleep(5000);//if can't connect: wait some time and throw
throw e;
}
shouldsync=initInbox()||shouldsync;//if inbox was null or closed: needs to sync
if(shouldsync)//if needs to sync
{
getNewMail();//gets new unseen mail
shouldsync=false;//already refreshed, clear sync "flag"
}
while (keppAliveConnection) {//if sould keep idling "forever"
synchronized (idleLock){}//MessageCountListener may be doing some work... wait for it
isIdling = true; //set isIdling "flag"
handler.removeCallbacksAndMessages(null);//clears refresh scheduled tasks
handler.postDelayed(new Runnable() {
#Override
public void run() {
refresh();
}
},1200000);//Schedule a refresh in 20 minutes
inbox.idle();//start idling
if(refreshThread !=null && refreshThread.isAlive())
refreshThread.interrupt();//if the refresher thread is active: interrupt. I thing this is not necessary at this point, but not shure
handler.removeCallbacksAndMessages(null);//clears refresh scheduled tasks
isIdling=false;//clear isIdling "flag"
if(shouldsync)
break;//if ordered to sync... break. The loop will handle it upstairs.
synchronized (idleLock){}//MessageCountListener may be doing some work... wait for it
}
}
catch (Exception e) {
//if the refresher thread is active: interrupt
//Why interrupt? refresher thread may be waiting for idle to return after "DONE" command, but if folder was closed and throws
//a FolderClosedException, then it could wait forever...., so... interrupt.
if (refreshThread != null && refreshThread.isAlive())
refreshThread.interrupt();
handler.removeCallbacksAndMessages(null);//clears refresh scheduled tasks
}
}
}
},"IdlerThread");
th.start();
}
private synchronized void getNewMail()
{
shouldsync=false;
long uid=getLastSeen();//get last unprocessed mail
SearchTerm searchTerm=new UidTerm(uid,Long.MAX_VALUE);//search from las processed message to the las one.
IMAPSearchOperation so=new IMAPSearchOperation(searchTerm);
try {
so.run();//search new messages
final long[] is=so.uids();//get unprocessed messages count
if (is.length > 0) {//if some...
try {
//there are new messages
IMAPFetchMessagesOperation fop=new IMAPFetchMessagesOperation(is);
fop.run();//fetch new messages
if(fop.messages.length>0)
{
//process fetched messages (internally sets the last seen uid value & delete some...)
processMessages(fop.messages);
}
inbox.expunge();//expunge deleted messages if any
}
catch (Exception e)
{
//Do something
}
}
else
{
//Do something
}
}
catch (Exception e)
{
//Do something
}
}
private synchronized void initIMAP()
{
if(store==null)
{
store=new IMAPStore(mailSession,new URLName("imap",p.IMAPServer,p.IMAPPort,null,p.IMAPUser,p.IMAPPassword));
}
}
private boolean connectIMAP() throws MessagingException {
try {
store.connect(p.IMAPServer, p.IMAPPort, p.IMAPUser, p.IMAPPassword);
return true;
}
catch (IllegalStateException e)
{
return false;
}
}
//returns true if the folder was closed or null
private synchronized boolean initInbox() throws MessagingException {
boolean retVal=false;
if(inbox==null)
{//if null, create. This is called after initializing store
inbox = (IMAPFolder) store.getFolder("INBOX");
inbox.addMessageCountListener(countListener);
retVal=true;//was created
}
if(!inbox.isOpen())
{
inbox.open(Folder.READ_WRITE);
retVal=true;//was oppened
}
return retVal;
}
private MessageCountListener countListener= new MessageCountAdapter() {
#Override
public void messagesAdded(MessageCountEvent ev) {
synchronized (idleLock)
{
try {
processMessages(ev.getMessages());//process the new messages, (internally sets the last seen uid value & delete some...)
inbox.expunge();//expunge deleted messajes if any
} catch (MessagingException e) {
//Do something
}
}
}
};
}
The problem is: Sometimes when the user is refreshing or the app auto-refreshes, in the Alive Connection mode, one or both of this conditions keeps my app from getting new messages. This is from the javamail source code.
1: The IdlerThread enters monitor state in:
//I don't know why sometimes it enters monitor state here.
private synchronized void throwClosedException(ConnectionException cex)
throws FolderClosedException, StoreClosedException {
// If it's the folder's protocol object, throw a FolderClosedException;
// otherwise, throw a StoreClosedException.
// If a command has failed because the connection is closed,
// the folder will have already been forced closed by the
// time we get here and our protocol object will have been
// released, so if we no longer have a protocol object we base
// this decision on whether we *think* the folder is open.
if ((protocol != null && cex.getProtocol() == protocol) ||
(protocol == null && !reallyClosed))
throw new FolderClosedException(this, cex.getMessage());
else
throw new StoreClosedException(store, cex.getMessage());
}
2: The "refresherThread" enters wait state in:
void waitIfIdle() throws ProtocolException {
assert Thread.holdsLock(messageCacheLock);
while (idleState != RUNNING) {
if (idleState == IDLE) {
protocol.idleAbort();
idleState = ABORTING;
}
try {
// give up lock and wait to be not idle
messageCacheLock.wait();//<-----This is the line is driving me crazy.
} catch (InterruptedException ex) { }
}
}
As one of both of this threads "stops" running (wait & monitor state) my app is useless when reach this condition. In my country the mobile data network is very unstable, slow & expensive(GSM) So it must be failure resilient and take care about every transferred bit.
I guess the problem arises when the connection silently fails and the refresherThread starts to do its job. It issues a DONE command if idle is active, but, as the connection is gone, when idle tries to throw a FolderClosedException, one or both threads gets locked indefinitely.
So, my question is: Why is this situation arising and how to prevent it? How can I keep the idle loop securely running without getting locked?
I've tried a lot of things till exhaustion with no results.
Here are some threads I've read without getting a solution to my problem. In my country internet is EXTREMELY expensive too, so I can't research as much as I want, nor list all the urls I've visited looking for information.
JavaMail: Keeping IMAPFolder.idle() alive
JavaMail: Keeping IMAPFolder.idle() alive
Javamail : Proper way to issue idle() for IMAPFolder
Please, excuse my english. Any suggestion will be greatly appreciated. I've heard about this site strictness, so please be gentle, I'm new over here.
Be sure to set the timeout properties to make sure you don't hang waiting for a dead connection or server.
Instead of issuing a nop command directly, you should call Folder.isOpen or Folder.getMessageCount; they'll issue the nop command if needed.
If the folder is closed asynchronously (FolderClosedException), you'll need to restart the idle loop.

Run swingworkers sequentially with semaphore

I have a panel with a JTabbedpane and in every tab you can set parameters to execute a query. When one query is busy retrieving his data from the database, you can already open a new tab to set the new parameters. To avoid overload on the database only one query may be executed at once. But when you click execute the program must remember which queries to execute in the right order. During the execution a loader icon is shown and the GUI may not be frozen, because there is a stop button you can click to stop the execution.
I used a swingworker to avoid the GUI from blocking while executing the query and that works fine. But now I want to prevent the next query to start before the previous has finished. In a model, common for the whole panel, I initialized a semaphore: private final Semaphore semaphore = new Semaphore(1, true);
This is the code which starts the swingworker (I've added println commands to see which is started, stopped or finished)
private void doStoredQuery() {
try {
semaphore.acquire();
System.out.println(queryName + "started");
worker.execute();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
And this is my swingworker (initializeWorker() is called from the constructor of the main class):
private SwingWorker<StoredQueryDataModel, Integer> initializeWorker() {
worker = new SwingWorker<StoredQueryDataModel, Integer>() {
#Override
protected StoredQueryDataModel doInBackground() throws Exception {
try {
StoredQueryDataModel dataModel = null;
publish(0);
try {
dataModel = new StoredQueryDataModel(queryRunner, ldbName, queryName, params);
} catch (S9SQLException e) {
//
} catch (Throwable e) {
showErrorMessage(e);
}
return dataModel;
}
finally {
semaphore.release();
System.out.println(queryName + "finished");
}
}
#Override
protected void process(List<Integer> chunks) {
//ignore chunks, just reload loader icon
panel.repaint();
}
#Override
protected void done() {
String error;
try {
result = get();
error = null;
} catch (Exception e) {
error = e.getMessage();
}
if(result == null) {
semaphore.release();
System.out.println(queryName + " stopped");
}
if(error == null) {
// process result
}
else {
showErrorMessage(new Throwable(error));
}
}
};
return worker;
}
I've tried putting the acquire and release on other positions in the code, but nothing seems to work. I am bot in Swingworker and sempahores quite new... Can someone help?
I have found the problem: the semaphore had to be a static variable. In my code there were as many semaphores as there are tabs, which caused them to run at the same time instead of sequentially.

How to get an exception raised from a long running background Task without having main thread to wait

I want to perform some long running operation (e.g. listening to some event raised by OS) on the background thread. Most of the times, operation will run continuously without any problem. But in certain rare conditions, OS level API sends some error code and I need to raise exception from background thread which has to be propagated to the main thread to show it to the user of my WinFrom application.
I had decided to use BackgroundWorker for this. But .NET 4.0 provides Task class of the Task Parallel Library which is a better option as per various blogs on the TPL.
In my application, I have to kick off the background task before actual form is shown. Since actual code is quite complex, I have written some sample code simulating real time problem:
public static Task task;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
ThreadTest tt = new ThreadTest();
task = new Task(() => tt.PerformTask("hi"));
task.Start();
try
{
task.Wait();
}
catch (AggregateException aggregateException)
{
// Handle exception here.
}
Application.Run(new Form1());
}
In this code, I never see the main form simply because background task keeps running without exception and task.Wait() call makes the current thread waiting until background task finishes!
Can I use TPL's Task for such scenarios where main thread should not wait until background task is finished but at the same time, it should get exception details whenever exception is raised from the background task?
In above code, one of the solutions could be to move the task creation code at some later stage. But my question is more academic in this case.
Yes you can. Please see the code below.
The program code is:
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
Task longRunningTask = new Task((state) =>
{
LongRunningWork.DoWork( cancellationTokenSource.Token);
},cancellationTokenSource.Token,TaskCreationOptions.LongRunning);
var newForm = new Form1(cancellationTokenSource);
new Thread((state) =>
{
longRunningTask.Start();
try
{
longRunningTask.Wait();
}
catch (AggregateException exception)
{
Action<Exception> showError = (ex) => MessageBox.Show(state as Form, ex.Message);
var mainForm = state as Form;
if (mainForm != null)
{
mainForm.BeginInvoke(showError, exception.InnerException);
}
}
}).Start(newForm);
Application.Run(newForm);
And the code for the long running task is:
public class LongRunningWork
{
public static void DoWork( CancellationToken cancellationToken)
{
int iterationCount = 0;
//While the
while (!cancellationToken.IsCancellationRequested &&iterationCount <5)
{
//Mimic that we do some long jobs here
Thread.Sleep(1000);
iterationCount++;
//The jobs may throw the exception on the specific condition
if (iterationCount ==5)
{
throw new InvalidOperationException("Invalid action");
}
}
//cancel the task
cancellationToken.ThrowIfCancellationRequested();
}
}
Finally, the code for the Form1 which includes a exit button, whose function is to terminate the program on clicking.
public partial class Form1 : Form
{
private CancellationTokenSource _cancellationTokenSource;
public Form1()
{
InitializeComponent();
}
public Form1(CancellationTokenSource cancellationTokenSource):this()
{
_cancellationTokenSource = cancellationTokenSource;
}
private void exitBtn_Click(object sender, EventArgs e)
{
//Cancel out the task
if (_cancellationTokenSource != null)
{
_cancellationTokenSource.Cancel();
}
//Exit the program
Application.Exit();
}
}
Start your long running operation from the form itself rather than before the form is created. Remember that Application.Run() starts a message loop on the current thread, but that means you can use that message loop to poll your task from the Timer class.
class Form1 : Form
{
private Timer PollingTimer;
private Task BackgroundTask;
public Form1()
{
InitializeComponent();
// Begin the background task.
ThreadTest tt = new ThreadTest();
this.BackgroundTask = new Task(() => tt.PerformTask("hi"));
this.BackgroundTask.Start();
// Monitor the task's status by polling it regularly.
this.PollingTimer = new Timer();
this.PollingTimer.Interval = 1000; // In milliseconds.
this.PollingTimer.Tick += timerCallback;
this.PollingTimer.Start();
}
private timerCallback(object sender, EventArgs e)
{
if (this.BackgroundTask.IsFaulted)
{
// Exception information is in BackgroundTask.Exception.
}
}
}
If you dislike polling (which I do), you'll need to catch the exception from your task and marshall it back to your UI thread. The best way to do that is simply not catch the exception in the task itself and provide a continuation method which will only execute on error.
class Form1 : Form
{
private Task BackgroundTask;
public Form1()
{
InitializeComponent();
// Capture the UI thread context.
// (Note, it may be safer to run this in the Form.Load event than the constructor.
var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
// Begin the background task.
ThreadTest tt = new ThreadTest();
this.BackgroundTask = new Task(() => tt.PerformTask("hi"))
// Schedule a continuation to be executed after the task is completed.
.ContinueWith((t,arg) =>
{
// Exception information is in t.Exception
},null, null,
// Only execute the continuation if the task throws an exception.
TaskContinuationOptions.OnlyOnFaulted,
// Execute the continuation on the UI thread we captured above.
uiContext);
this.BackgroundTask.Start();
}
}
MSDN references for Task.ContinueWith() and TaskScheduler.FromCurrentSynchronizationContext().
And, if you have the luxury of .NET 4.5 with async and await:
class Form1 : Form
{
private Task BackgroundTask;
public Form1()
{
InitializeComponent();
}
private async void Form1_Load(object sender, EventArgs e)
{
ThreadTest tt = new ThreadTest();
try
{
// Move your Task creation and start logic into a method.
await tt.RunAsync();
}
catch (Exception ex)
{
// Really smart compiler writers make sure you're on the right thread
// and everything Just Works(tm).
}
}
}

Windows service & mutilthreading

I have a windows service, which is executed regular intervals... Here is the code snippet:
protected override void OnStart(string[] args)
{
tickTack = new Timer(10000);
tickTack.Elapsed += new ElapsedEventHandler(tickTack_Elapsed);
tickTack.Start();
}
protected override void OnStop()
{
tickTack.Stop();
}
private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
objProc = new Processing();
objProc.start();
}
In my start() method of Processing Class do my actual work like below.
public void start()
{
try
{
Process_Requests();
Process_Exports();
}
catch (Exception ex)
{
ErrorLogs.SaveError(ex, "");
}
}
How does the execution is happen when the execution done in a single thread??? For example, the first method takes time for execution then what about second method????
Now I want to call Process_request() and Preocess_export() methods. Each method should connect to multiple databases. In this situation, would I need to create new thread for each connection and do my work... I am not sure.
public void start()
{
try
{
#region
sqlConObjects = new List<SqlConnection>();
// Here i am getting multiple connection strings
List<string> conStrings = GetConnectionStrings();
foreach (string strCon in conStrings)
{
SqlConnection sqlCon = new SqlConnection(strCon);
sqlConObjects.Add(sqlCon);
}
foreach (SqlConnection sqlCon in sqlConObjects)
{
//sqlCon.Open();
Thread t = new Thread(ProcessRequest);
t.Start((object)sqlCon);
Thread t1=new Thread(ProcessExports);
t1.Start((object)sqlCon);
}
#endregion
}
catch (Exception ex)
{
ErrorLogs.SaveError(ex, "");
}
}
Can anyone please explain how to do this... is thread is created or no need??? How should the execution is happen if we are not creating a thread for each connection object.
Timer works on ThreadPool
From MSDN
The callback method executed by the timer should be reentrant, because it is called on ThreadPool threads. The callback can be executed simultaneously on two thread pool threads if the timer interval is less than the time required to execute the callback, or if all thread pool threads are in use and the callback is queued multiple times.
Also in your's code you don't keep reference to timer object and it will be collected.
As for me you should use ThreadPool. Createing a lot of threads is bad practice

How to implement cancellable worker thread

I'm trying to implement a cancellable worker thread using the new threading constructs in System.Threading.Tasks namespace.
So far I have have come up with this implementation:
public sealed class Scheduler
{
private CancellationTokenSource _cancellationTokenSource;
public System.Threading.Tasks.Task Worker { get; private set; }
public void Start()
{
_cancellationTokenSource = new CancellationTokenSource();
Worker = System.Threading.Tasks.Task.Factory.StartNew(
() => RunTasks(_cancellationTokenSource.Token),
_cancellationTokenSource.Token
);
}
private static void RunTasks(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
Thread.Sleep(1000); // simulate work
}
}
public void Stop()
{
try
{
_cancellationTokenSource.Cancel();
Worker.Wait(_cancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
// OperationCanceledException is expected when a Task is cancelled.
}
}
}
When Stop() returns I expect Worker.Status to be TaskStatus.Canceled.
My unit tests have shown that under certain conditions Worker.Status remains set to TaskStatus.Running.
Is this a correct way to implement a cancellable worker thread?
I believe that the problem is in your call to
Worker.Wait(_cancellationTokenSource.Token);
That's waiting for the token to be signalled - which it already is, because you've just called Cancel(). If you change that to just
Worker.Wait();
then I believe you'll see a state of RanToCompletion. You won't see Canceled, because your task isn't throwing OperationCanceledException. If you change your RunTasks method to call
cancellationToken.ThrowIfCancellationRequested()
at the end, then you'll need to catch an AggregateException in Stop - but then you'll see a state of Canceled at the end.
At least, that's what my experimentation shows :)

Resources