Multi-threading using AutoResetEvent [modified]
-
Hello, C# 2005 I am using a background worker to process some login information. However, the background worker has to stop and wait for 2 events to happen. Once these have finished the background worker can complete its job. They are callbacks that will call the Set() method of the AutoResetEvent. So I am using AutoResetEvent to set when these 2 events have finished. However, I seemed to be getting this error message "Exception has been thrown by the target of an invocation." And Inner exception Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index". The exception usually fires when the registration success leaves scope. Many thanks for any advice,
// Waiting for 'Account in use' and 'Register success or failure'
AutoResetEvent[] loginWaitEvents = new AutoResetEvent[]
{
new AutoResetEvent(false),
new AutoResetEvent(false)
};private void bgwProcessLogin_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("Wait until event is set or timeout");
loginWaitEvents[0].WaitOne(3000, true);if (this.accountInUseFlag) { if (this.lblRegistering.InvokeRequired) { this.lblRegistering.Invoke(new UpdateRegisterLabelDelegate(this.UpdateRegisterLabel), "Account in use"); } else { this.lblRegistering.Text = "Account in use"; } // Failed attemp e.Cancel = true; // Reset flag this.accountInUseFlag = false; return; } else { // Report current progress this.bgwProcessLogin.ReportProgress(7, "Account accepted"); } Console.WriteLine("Just Wait the result of successfull login or not"); loginWaitEvents\[1\].WaitOne(); if (this.registerSuccess) { // Report current progress this.bgwProcessLogin.ReportProgress(7, "Register Succesfull"); // Reset flag this.registerSuccess = false; } else { if (this.lblRegistering.InvokeRequired) { this.lblRegisteri
-
Hello, C# 2005 I am using a background worker to process some login information. However, the background worker has to stop and wait for 2 events to happen. Once these have finished the background worker can complete its job. They are callbacks that will call the Set() method of the AutoResetEvent. So I am using AutoResetEvent to set when these 2 events have finished. However, I seemed to be getting this error message "Exception has been thrown by the target of an invocation." And Inner exception Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index". The exception usually fires when the registration success leaves scope. Many thanks for any advice,
// Waiting for 'Account in use' and 'Register success or failure'
AutoResetEvent[] loginWaitEvents = new AutoResetEvent[]
{
new AutoResetEvent(false),
new AutoResetEvent(false)
};private void bgwProcessLogin_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("Wait until event is set or timeout");
loginWaitEvents[0].WaitOne(3000, true);if (this.accountInUseFlag) { if (this.lblRegistering.InvokeRequired) { this.lblRegistering.Invoke(new UpdateRegisterLabelDelegate(this.UpdateRegisterLabel), "Account in use"); } else { this.lblRegistering.Text = "Account in use"; } // Failed attemp e.Cancel = true; // Reset flag this.accountInUseFlag = false; return; } else { // Report current progress this.bgwProcessLogin.ReportProgress(7, "Account accepted"); } Console.WriteLine("Just Wait the result of successfull login or not"); loginWaitEvents\[1\].WaitOne(); if (this.registerSuccess) { // Report current progress this.bgwProcessLogin.ReportProgress(7, "Register Succesfull"); // Reset flag this.registerSuccess = false; } else { if (this.lblRegistering.InvokeRequired) { this.lblRegisteri
From the exception text, the exception seems to be occurring in
UpdateRegisterLabel
. Try debugging that method by placing a breakpoint at the start of the method.Regards Senthil [MVP - Visual C#] _____________________________ My Home Page |My Blog | My Articles | My Flickr | WinMacro
-
Hello, C# 2005 I am using a background worker to process some login information. However, the background worker has to stop and wait for 2 events to happen. Once these have finished the background worker can complete its job. They are callbacks that will call the Set() method of the AutoResetEvent. So I am using AutoResetEvent to set when these 2 events have finished. However, I seemed to be getting this error message "Exception has been thrown by the target of an invocation." And Inner exception Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index". The exception usually fires when the registration success leaves scope. Many thanks for any advice,
// Waiting for 'Account in use' and 'Register success or failure'
AutoResetEvent[] loginWaitEvents = new AutoResetEvent[]
{
new AutoResetEvent(false),
new AutoResetEvent(false)
};private void bgwProcessLogin_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("Wait until event is set or timeout");
loginWaitEvents[0].WaitOne(3000, true);if (this.accountInUseFlag) { if (this.lblRegistering.InvokeRequired) { this.lblRegistering.Invoke(new UpdateRegisterLabelDelegate(this.UpdateRegisterLabel), "Account in use"); } else { this.lblRegistering.Text = "Account in use"; } // Failed attemp e.Cancel = true; // Reset flag this.accountInUseFlag = false; return; } else { // Report current progress this.bgwProcessLogin.ReportProgress(7, "Account accepted"); } Console.WriteLine("Just Wait the result of successfull login or not"); loginWaitEvents\[1\].WaitOne(); if (this.registerSuccess) { // Report current progress this.bgwProcessLogin.ReportProgress(7, "Register Succesfull"); // Reset flag this.registerSuccess = false; } else { if (this.lblRegistering.InvokeRequired) { this.lblRegisteri
Without proper formatting this is too hard to read. Use the PRE tags (not the code tags) to preserve formatting and indentation. :)
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
-
From the exception text, the exception seems to be occurring in
UpdateRegisterLabel
. Try debugging that method by placing a breakpoint at the start of the method.Regards Senthil [MVP - Visual C#] _____________________________ My Home Page |My Blog | My Articles | My Flickr | WinMacro
Hello, I solved my problem. It was something in the RunWorkercompleted. However, there is one more thing. The registerSuccess and AccountInUse are global because they are been accessed from 2 different threads. Would it be better to put a lock on them? Many thanks
-
Hello, I solved my problem. It was something in the RunWorkercompleted. However, there is one more thing. The registerSuccess and AccountInUse are global because they are been accessed from 2 different threads. Would it be better to put a lock on them? Many thanks
Getting a setting a bool is an atomic operation. However, in your code there are gaps between checking the variables for true and setting them to false. It is possible to fall through on true and the variable then gets set to true again, whereupon you set it to false. This may not matter, but is a matter of concern.
Anyone who thinks he has a better idea of what's good for people than people do is a swine. - P.J. O'Rourke
-
Getting a setting a bool is an atomic operation. However, in your code there are gaps between checking the variables for true and setting them to false. It is possible to fall through on true and the variable then gets set to true again, whereupon you set it to false. This may not matter, but is a matter of concern.
Anyone who thinks he has a better idea of what's good for people than people do is a swine. - P.J. O'Rourke
-
Hello, When you say that setting a bool is a atomic operation. Does that mean the the operation will has to complete all of it, or fail? What would be the difference in setting either a string or a integer? Thanks,
steve_rm wrote:
Does that mean the the operation will has to complete all of it, or fail?
Yes, the CLR guarantees that all operations on datatypes less than or equal to the size of a native pointer will be atomic. So on a 32 bit machine, storing and retrieving integers is atomic, while the same operations on longs (64 bits in size) are not.
Regards Senthil [MVP - Visual C#] _____________________________ My Home Page |My Blog | My Articles | My Flickr | WinMacro
-
Hello, When you say that setting a bool is a atomic operation. Does that mean the the operation will has to complete all of it, or fail? What would be the difference in setting either a string or a integer? Thanks,
"atomic" means the value will get set at once - other threads reading the value at the same time will either see the old value or the new value, nothing "in between". Reading/writings strings and ints is also atomic. However, reading/writing longs (or other value types >32 bit) is NOT atomic: you might end up reading 32 bits from the old value and the other 32 bits from the new value. But even though it's atomic, I'd suggest that you still put a lock around it. For example, in this code: Initialization:
int a = 0, b = 0, c = 0;
Thread 1:
a = 1;
if (b == 0) c++;Thread 2:
b = 1;
if (a == 0) c++;From a simple look at the code, it seems that c will be 0 or 1. c shouldn't be 2 because "c++" cannot run on both threads - it's incremented only if the other thread hasn't set its flag (a or b) yet. Writes and reads to a,b are atomic. The increment of c is not atomic (read and write of c are atomic, but the combination read-increment-write isn't atomic). But actually, it is possible for both "c++" to execute, so c could become 2! (though only on dual-core machines) It's also possible that both "c++" execute but c still becomes only 1. Both "c++" can execute because x86 CPUs are allowed to move the "read"-instruction from the if-condition above the write-instruction from the assignment above (or they might execute the read and write in parallel). I've tested this myself using hand-written assembler code, an Intel Core Duo WILL move reads above writes where possible! You'll have to insert a memory barrier instruction to prevent the CPU from doing that. In C#, the "volatile" keyword can be used for some kinds of memory barriers: volatile writes have release semantics, volatile reads have acquire semantics. That's sufficient for many cases of unsynchronized access to variables, but it doesn't help in the example I gave above - we need a full memory barrier there. -> If you access shared variables without locks, might have to insert a memory barriers to synchronize the memory between CPUs. It's extremely hard to get those right. So I would suggest that you keep it simple and always use a lock.