"One or more exceptions" occurred at Task.Start()
-
I have a form application with a button and a listbox. When I click the button, I launch about 10 tasks and then do a wait on each of the tasks. When I try to run this from Visual Studio 2013 in Debug mode, I get an exception "One or more errors occurred" at Task.Start() itself, but when I run this outside of the debugger, then it works fine. Is this a Visual Studio issue? Any light on this would be helpful. Please find the code snippet below:
private void SynchronousWait200ms()
{
Thread.Sleep(200);
listBox.Items.Add("Wait 200 ms, Thread Id = " + Thread.CurrentThread.ManagedThreadId);
}private void TaskRunButton_Click1(object sender, EventArgs e)
{
listBox.Items.Clear();
try
{
List<Task> tsk1 = new List<Task>();for (int i = 0; i < 10; i++) { tsk1.Add(new Task(SynchronousWait200ms)); tsk1\[i\].Start(); tsk1\[i\].Wait(); } listBox.Items.Add("------------"); } catch (Exception ex) { string msg = ex.Message; }
}
-
I have a form application with a button and a listbox. When I click the button, I launch about 10 tasks and then do a wait on each of the tasks. When I try to run this from Visual Studio 2013 in Debug mode, I get an exception "One or more errors occurred" at Task.Start() itself, but when I run this outside of the debugger, then it works fine. Is this a Visual Studio issue? Any light on this would be helpful. Please find the code snippet below:
private void SynchronousWait200ms()
{
Thread.Sleep(200);
listBox.Items.Add("Wait 200 ms, Thread Id = " + Thread.CurrentThread.ManagedThreadId);
}private void TaskRunButton_Click1(object sender, EventArgs e)
{
listBox.Items.Clear();
try
{
List<Task> tsk1 = new List<Task>();for (int i = 0; i < 10; i++) { tsk1.Add(new Task(SynchronousWait200ms)); tsk1\[i\].Start(); tsk1\[i\].Wait(); } listBox.Items.Add("------------"); } catch (Exception ex) { string msg = ex.Message; }
}
No, you still get the problem, just you don't see it because the thread that fails isn't the main thread. You can't update UI controls from a non UI thread - you are getting a cross threading exception. Use Invoke to move teh listBox update back onto the UI thread and it should be fine.
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
-
I have a form application with a button and a listbox. When I click the button, I launch about 10 tasks and then do a wait on each of the tasks. When I try to run this from Visual Studio 2013 in Debug mode, I get an exception "One or more errors occurred" at Task.Start() itself, but when I run this outside of the debugger, then it works fine. Is this a Visual Studio issue? Any light on this would be helpful. Please find the code snippet below:
private void SynchronousWait200ms()
{
Thread.Sleep(200);
listBox.Items.Add("Wait 200 ms, Thread Id = " + Thread.CurrentThread.ManagedThreadId);
}private void TaskRunButton_Click1(object sender, EventArgs e)
{
listBox.Items.Clear();
try
{
List<Task> tsk1 = new List<Task>();for (int i = 0; i < 10; i++) { tsk1.Add(new Task(SynchronousWait200ms)); tsk1\[i\].Start(); tsk1\[i\].Wait(); } listBox.Items.Add("------------"); } catch (Exception ex) { string msg = ex.Message; }
}
Why are you starting a new task and then immediately waiting for it? You're blocking the UI thread waiting for a background thread to complete, so you might as well just do the work on the UI thread. I suspect the reason you're getting an exception is because you're updating a UI control from a non-UI thread. You will need to use the
Invoke
method to ensure that the updates only happen on the UI thread. Unfortunately, since you've chosen to block the UI thread waiting for the background thread to complete, this won't work - the UI thread is blocked waiting for the background thread to complete, and the background thread is blocked waiting for the UI thread to process theInvoke
message. You might be able to work around the problem by usingBeginInvoke
instead, which won't block the background thread. However, this will change the behaviour of your code, as the list items will not be added in the same sequence. If you're using .NET 4.5, try usingasync
/await
instead:private async Task SynchronousWait200ms()
{
await Task.Delay(200);
listBox.Items.Add("Wait 200 ms, Thread Id = " + Thread.CurrentThread.ManagedThreadId);
}private async void TaskRunButton_Click1(object sender, EventArgs e)
{
listBox.Items.Clear();for (int i = 0; i < 10; i++) { await SynchronousWait200ms(); } listBox.Items.Add("------------");
}
That should work, but you'll get the same thread ID for each item, as the code will be marshalled back to the UI thread. Perhaps if you explain what you're trying to achieve, we might be able to help.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
No, you still get the problem, just you don't see it because the thread that fails isn't the main thread. You can't update UI controls from a non UI thread - you are getting a cross threading exception. Use Invoke to move teh listBox update back onto the UI thread and it should be fine.
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
OriginalGriff wrote:
Use Invoke to move teh listBox update back onto the UI thread and it should be fine.
Or it would be fine, if he wasn't blocking the UI thread waiting for the background thread to complete! :doh:
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
OriginalGriff wrote:
Use Invoke to move teh listBox update back onto the UI thread and it should be fine.
Or it would be fine, if he wasn't blocking the UI thread waiting for the background thread to complete! :doh:
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Good point - since the Invoke call waits for the delegate to return a value, you should get a deadlock.
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
-
No, you still get the problem, just you don't see it because the thread that fails isn't the main thread. You can't update UI controls from a non UI thread - you are getting a cross threading exception. Use Invoke to move teh listBox update back onto the UI thread and it should be fine.
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
I don't see any failing thread, because I am getting the values in the list box correctly, but as you mentioned, it may fail at any time. Thanks very much for your valuable inputs. I will work on this and update further...
-
Why are you starting a new task and then immediately waiting for it? You're blocking the UI thread waiting for a background thread to complete, so you might as well just do the work on the UI thread. I suspect the reason you're getting an exception is because you're updating a UI control from a non-UI thread. You will need to use the
Invoke
method to ensure that the updates only happen on the UI thread. Unfortunately, since you've chosen to block the UI thread waiting for the background thread to complete, this won't work - the UI thread is blocked waiting for the background thread to complete, and the background thread is blocked waiting for the UI thread to process theInvoke
message. You might be able to work around the problem by usingBeginInvoke
instead, which won't block the background thread. However, this will change the behaviour of your code, as the list items will not be added in the same sequence. If you're using .NET 4.5, try usingasync
/await
instead:private async Task SynchronousWait200ms()
{
await Task.Delay(200);
listBox.Items.Add("Wait 200 ms, Thread Id = " + Thread.CurrentThread.ManagedThreadId);
}private async void TaskRunButton_Click1(object sender, EventArgs e)
{
listBox.Items.Clear();for (int i = 0; i < 10; i++) { await SynchronousWait200ms(); } listBox.Items.Add("------------");
}
That should work, but you'll get the same thread ID for each item, as the code will be marshalled back to the UI thread. Perhaps if you explain what you're trying to achieve, we might be able to help.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Thanks very much for your thoughts. Yes, Invoke also blocks as you mentioned. BeginInvoke solves the issue, but sequence goes wrong. Regarding async / await, I am aware of it. In the project from where I took the code and posted here, it has async / await sample also. I am working on a sample for async / await. In that same sample I wanted to add Task.Start() as an example to demonstrate the use of Task.Wait() via another button on the UI. That's the reason I am doing wait immediately after Task.Start() :)
-
Good point - since the Invoke call waits for the delegate to return a value, you should get a deadlock.
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
Thanks to both of you for your valuable help. Changed it as shown below and got it working without loosing sequence and with corresponding thread id...
private void TaskRunButton_Click(object sender, EventArgs e)
{
// clear the list before writing
listBox.Items.Clear();
Task demoTask = new Task(DemoTask);
demoTask.Start();
}private void DemoTask()
{
try
{
List<Task> tsk1 = new List<Task>();
List<Task> tsk2 = new List<Task>();for (int i = 0; i < 10; i++) { tsk1.Add(new Task(TaskDemoWait100ms)); tsk2.Add(new Task(TaskDemoWaitWait200ms)); } for (int i = 0; i < 10; i++) { tsk1\[i\].Start(); tsk2\[i\].Start(); tsk2\[i\].Wait(); listBox.BeginInvoke(new separatorDelegate(() => { listBox.Items.Add("------------"); })); } } catch (Exception ex) { string msg = ex.Message; }
}
delegate void taskdelegate(int threadId);
delegate void separatorDelegate();private void TaskDemoWait100ms()
{
Thread.Sleep(100);
object[] param = new object[1];param\[0\] = (object)Thread.CurrentThread.ManagedThreadId; listBox.BeginInvoke(new taskdelegate((int threadId) => { listBox.Items.Add("Wait 100 ms, Thread Id = " + threadId); }), param);
}
private void TaskDemoWaitWait200ms()
{
Thread.Sleep(200);
object[] param = new object[1];param\[0\] = (object)Thread.CurrentThread.ManagedThreadId; listBox.BeginInvoke(new taskdelegate((int threadId) => { listBox.Items.Add("Wait 200 ms, Thread Id = " + threadId); }), param);
}