I am running two long parallel tasks before Form_Load using
private void task1()
{
//Long task
}
private void task2()
{
//Long task
}
Task tsk=new Task(task1);
Task tsk2=new Task(task2);
Parallel.ForEach(new [] {tsk, tsk2},item=>item.Start());.
When the form opens after the tasks get completed,the form hangs when minimised by clicking the application button in taskbar , for 30 seconds, and then becomes active. Is there a way to overcome this?
Thanks
Edited To Add:
private static bool modalDisposed=false;
private ModalLoad ml = new ModalLoad();
private void Form_Load(object sender,EventArgs e)
{
ml.Show(this);
Task tsk=new Task(task1);
Task tsk2=new Task(task2);
Parallel.ForEach(new [] {tsk, tsk2},item=>item.Start());.
}
private void task1()
{
//long task
modalDisposed=true;
System.Threading.Thread.Sleep(100);
Application.OpenForms["ModalLoad"].Dispose();
}
private void task2()
{
while(!modalDisposed)
{
ml.updateLabel();
}
}
In the modal form, I update the label
private static int ui=0;
public void updateLabel()
{
this.Invoke((MethodInvoker)delegate
{
lblUI.Text=ui+"";
ui++;
});
}
Related
I have a WPF application in which lots of event initiate tasks. Here's how I am doing it. But I am not happy about how it looks now
var task = UpdatePersonModelAsync();
taskCollection.Add(task);
RaisePropertyChanged(nameof(IsUpdateInProgress));
await task;
taskCollection.Remove(task);
RaisePropertyChanged(nameof(IsUpdateInProgress));
The property which shows/hides spinner
public bool IsUpdateInProgress => taskCollection.Count > 0;
I was going through the Progress<T> it seems like a call back.
When all the incoming tasks are completed a small spinner will be hidden.
You probably should use await Task.WhenAll(taskCollection.ToArray()); for waiting all the tasks you need to wait. After that, put the code for hiding the spinner below the await statement.
I tried using a CustomTaskScheduler. I got it from https://www.infoworld.com/article/3063560/application-development/building-your-own-task-scheduler-in-c.html
http://www.codeguru.com/csharp/article.php/c18931/Understanding-the-NET-Task-Parallel-Library-TaskScheduler.htm
As tasks are created from various calls, I use the CustomTaskScheduler in Task.Factory.StartNew.
On debugging, I can get hits on QueueTask but Execute isn't getting called. What am I missing?
public sealed class CustomTaskScheduler : TaskScheduler, IDisposable
{
public delegate void TaskStartedHandler(Task sender);
public delegate void AllTasksCompletedHandler(IEnumerable<Task> sender);
public event TaskStartedHandler TaskStarted;
public event AllTasksCompletedHandler AllTasksCompleted;
private BlockingCollection<Task> tasksCollection = new BlockingCollection<Task>();
private readonly Thread mainThread = null;
public CustomTaskScheduler()
{
mainThread = new Thread(new ThreadStart(Execute));
if (!mainThread.IsAlive)
{
mainThread.Start();
}
}
private void Execute()
{
foreach (var task in tasksCollection.GetConsumingEnumerable())
{
var isStarted = TryExecuteTask(task);
if (isStarted && TaskStarted != null)
{
TaskStarted(task);
}
}
if(tasksCollection.GetConsumingEnumerable().All(m => m.IsCompleted))
{
AllTasksCompleted?.Invoke(tasksCollection.GetConsumingEnumerable());
}
}
protected override IEnumerable<Task> GetScheduledTasks()
{
return tasksCollection.ToArray();
}
protected override void QueueTask(Task task)
{
if (task != null)
{
tasksCollection.Add(task);
}
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return false;
}
private void Dispose(bool disposing)
{
if (!disposing)
{
return;
}
tasksCollection.CompleteAdding();
tasksCollection.Dispose();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
The code is not yet complete. It would be great if someone can point to right direction
Here's a new version
public class TaskTracker
{
public delegate void AllTasksCompletedHandler(object sender);
public delegate void TaskStartedHandler();
public event AllTasksCompletedHandler AllTasksCompleted;
public event TaskStartedHandler TaskStarted;
private object syncLock = new object();
private SynchronizedCollection<Task> tasksCollection;
private bool isTaskStartedNotified;
private readonly uint delay;
public TaskTracker(uint delayBeforeRemovingTasks)
{
tasksCollection = new SynchronizedCollection<Task>();
delay = delayBeforeRemovingTasks;
}
public void Add(Task task)
{
if (!isTaskStartedNotified)
{
isTaskStartedNotified = true;
TaskStarted?.Invoke();
}
task.ContinueWith(t =>
{
RemoveTask(t);
});
tasksCollection.Add(task);
}
private async void RemoveTask(Task task)
{
await Task.Delay(300);
await Task.Run(() =>
{
tasksCollection.Remove(task);
if (tasksCollection.Count == 0)
{
isTaskStartedNotified = false;
AllTasksCompleted?.Invoke(tasksCollection);
}
});
}
}
I need a windows service to transfer data to another SQL server every 10 minutes.
This service is scheduled with a periodicity of 10 minutes and executes 5 stored procedures that transfer the data
If machine restarts the service should work again.
So, What's best way for this service?
My solution is as below. But this service will stop after the first time:
static class Program
{
static void Main()
{
#if DEBUG
Service1 myService = new Service1();
myService.OnDebug();
#else
var servicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(servicesToRun);
#endif
}
public partial class Service1 : ServiceBase
{
Thread _worker;
static readonly AutoResetEvent StopRequest = new AutoResetEvent(false);
private static IDataRepository _dataRepository;
public Service1()
{
_dataRepository = new DataRepository();
InitializeComponent();
}
public void OnDebug()
{
OnStart(null);
}
protected override void OnStart(string[] args)
{
_worker = new Thread(DoWork);
_worker.Start();
}
protected override void OnStop()
{
StopRequest.Set();
_worker.Join();
}
private static void DoWork()
{
for (;;)
{
if (!_dataRepository.CheckInternetConnection()) return;
if (!_dataRepository.CheckDatabaseConnection()) return;
if (!_dataRepository.CheckOppositeDatabaseConnection()) return;
if (StopRequest.WaitOne(10000)) return;
List<Test> comeResults = _dataRepository.CheckNewDataCashRegister();
if (comeResults == null) return;
bool sendTest = _dataRepository.SendTest(comeResults);
if (!sendTest) return;
}
}
}
If you want to minimize external dependencies like using the Task Scheduler you can schedule the work in the service like this:
public partial class Service1 : ServiceBase
{
private readonly CancellationTokenSource _cancellationTokenSource;
private static IDataRepository _dataRepository;
public Service1()
{
_dataRepository = new DataRepository();
_cancellationTokenSource = new CancellationTokenSource();
InitializeComponent();
}
public void OnDebug()
{
OnStart(null);
}
protected override void OnStart(string[] args)
{
ScheduleWorkAsync();
}
protected override void OnStop()
{
_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();
}
private async Task ScheduleWorkAsync()
{
var _cancellationToken = _cancellationTokenSource.Token;
while (!_cancellationTokenSource.IsCancellationRequested)
{
try
{
DoWork();
await Task.Delay(TimeSpan.FromMinutes(10), _cancellationToken);
}
catch (OperationCanceledException)
{
}
}
}
private void DoWork()
{
if (!_dataRepository.CheckInternetConnection()) return;
if (!_dataRepository.CheckDatabaseConnection()) return;
if (!_dataRepository.CheckOppositeDatabaseConnection()) return;
List<Test> comeResults = _dataRepository.CheckNewDataCashRegister();
if (comeResults == null) return;
bool sendTest = _dataRepository.SendTest(comeResults);
if (!sendTest) return;
}
}
I need my WPF exe to start monitoring a queue as soon as it starts up, and then respond to messages as they come in.
The way I have it now is:
public partial class App
{
readonly BackgroundWorker _worker = new BackgroundWorker();
protected override void OnStartup(StartupEventArgs e)
{
_worker.DoWork += worker_DoWork;
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
_worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_worker.DoWork += worker_DoWork;
_worker.RunWorkerAsync();
}
static void worker_DoWork(object sender, DoWorkEventArgs e)
{
//do work
}
Obviously, this is pretty pathetic IMO.
Also, I don't like the approach of using while(true), inside the thread to keep it running indefinitely..
It's enough to read the messages from queue not permanently but periodically.
The common approach for this is using timer. For example, System.Threading.Timer.
public partial class App : Application
{
private System.Threading.Timer _msmqReadTimer;
public App()
{
_msmqReadTimer = new System.Threading.Timer(MsmqReadTimerTick);
_msmqReadTimer.Change(0, 1000); // call MsmqReadTimerTick immediatelly and each 1000 ms
}
private void MsmqReadTimerTick(object state)
{
// do work
// if you want to update some UI components after work, you should post this to UI thread dispatcher:
this.Dispatcher.Invoke(()=>
{
// logic for updating UI should be here
},
System.Windows.Threading.DispatcherPriority.Background);
}
}
I have a WinForms application that is calling a business class method that performs some heavy duty action taking about 5 seconds for each call. The main form calls this method in a loop. This loop can run from 10 times to maybe up to 10 thousand times.
The WinForms application sends a parameter to the business class and has an area to display the time taken for each method call and what the value returned by the method. How do I inform my main window and update a text area in the main winform with what the method has returned for each call?
Currently the data comes all at once after all the threads have finished. Is there a way to update the UI for all the iterations of the loop once the each call is done? I don't mind if it is done sequentially also.
The FORM
HeavyDutyClass hd;
public Form1()
{
InitializeComponent();
hd = new HeavyDutyClass();
}
//BUTTON CLICK
private void Start_Click(object sender, EventArgs e)
{
int filecount = 5000; //BAD - opening 5000 threads! Any other approach?
hd.FileProcessed += new EventHandler(hd_FileProcessed);
var threads = new Thread[filecount];
for (int i = 0; i < filecount; i++)
{
threads[i] = new Thread(() => { hd.LongRunningMethod(); });
threads[i].Start();
}
}
//BUSINESS CLASS EVENT THAT FIRES WHEN BUSINESS METHOD COMPELTES
void hd_FileProcessed(object sender, EventArgs e)
{
if (dgv.InvokeRequired)
{
dgv.Invoke((MethodInvoker)delegate { UpdateGrid(); });
}
}
private void UpdateGrid()
{
dgv.Rows.Add(1);
int i = dgv.Rows.Count;
dgv.Rows [ i-1].Selected = true;
dgv.FirstDisplayedScrollingRowIndex = i - 1;
}
The business HeavyDuty class
public event EventHandler FileProcessed;
public HeavyDutyClass()
{
}
protected virtual void OnMyEvent(EventArgs e)
{
if (FileProcessed != null)
{
FileProcessed(this, e);
}
}
public bool LongRunningMethod()
{
for (double i = 0; i < 199990000; i++)
{
//time consuming loop
}
OnMyEvent(EventArgs.Empty);
return true;
}
Add a Winforms Project, Drop a Label Control on the Form , Copy-Paste this code and Hit F5
[EDIT]: Updated with the business class comment from the user
NB: My form class is named Form3. You may have to change your Program.cs or vice-versa.
using System.ComponentModel;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class BusinessClass
{
public int MyFunction(int input)
{
return input+10;
}
}
public partial class Form3 : Form
{
private BackgroundWorker _worker;
BusinessClass _biz = new BusinessClass();
public Form3()
{
InitializeComponent();
InitWorker();
}
private void InitWorker()
{
if (_worker != null)
{
_worker.Dispose();
}
_worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_worker.DoWork += DoWork;
_worker.RunWorkerCompleted += RunWorkerCompleted;
_worker.ProgressChanged += ProgressChanged;
_worker.RunWorkerAsync();
}
void DoWork(object sender, DoWorkEventArgs e)
{
int highestPercentageReached = 0;
if (_worker.CancellationPending)
{
e.Cancel = true;
}
else
{
double i = 0.0d;
int junk = 0;
for (i = 0; i <= 199990000; i++)
{
int result = _biz.MyFunction(junk);
junk++;
// Report progress as a percentage of the total task.
var percentComplete = (int)(i / 199990000 * 100);
if (percentComplete > highestPercentageReached)
{
highestPercentageReached = percentComplete;
// note I can pass the business class result also and display the same in the LABEL
_worker.ReportProgress(percentComplete, result);
_worker.CancelAsync();
}
}
}
}
void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
// Display some message to the user that task has been
// cancelled
}
else if (e.Error != null)
{
// Do something with the error
}
}
void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = string.Format("Result {0}: Percent {1}",e.UserState, e.ProgressPercentage);
}
}
}
With this you can achieve Cancel functionality also very easily.
Observe that during initialisation, I set the WorkerSupportsCancellation = true & then I check for _worker.CancellationPending in the DoWork. So, if you want to cancel the process by a Cancel Button click, then you will write this code in the button handler- _worker.CancelAsync();
I am creating window in another thread. After closing the thread some of the resources window is not released from the memory. Because of this growing counter GDI Objects and User Objects in windows task manager. Graphics that not released are font and region. I haven't idea what is going on...
public class WaitingWindowManager
{
private Thread thread;
private bool canAbortThread = false;
private Window waitingWindow;
public void BeginWaiting()
{
this.thread = new Thread(this.RunThread);
this.thread.IsBackground = true;
this.thread.SetApartmentState(ApartmentState.STA);
this.thread.Start();
}
public void EndWaiting()
{
if (this.waitingWindow != null)
{
this.waitingWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => { this.waitingWindow.Close(); }));
while (!this.canAbortThread) { };
}
this.thread.Abort();
}
public void RunThread()
{
this.waitingWindow = new Window();
this.waitingWindow.Closed += new EventHandler(waitingWindow_Closed);
this.waitingWindow.ShowDialog();
}
void waitingWindow_Closed(object sender, EventArgs e)
{
this.canAbortThread = true;
}
}
And call :
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
WaitingWindowManager waitingWindowManager = new WaitingWindowManager();
waitingWindowManager.BeginWaiting();
Application.Current.Dispatcher.Thread.Join(5000);
waitingWindowManager.EndWaiting();
}
}
Remove your Closed eventhandler in your waitingWindow_Closed Event. It is causing your window to not be disposed. If you manually add events you need to make sure you remove them when finished.
I also noticed another Stackoverflow question that was pertaining to memory leaks in wpf. It referenced this article maybe this will help you.
Add Dispatcher.CurrentDispatcher.InvokeShutdown(); in your closing code. That should take care of any leaking memory.