Threading & Events Causing Cross Thread Problems

J

JasonX

Im having problems with my program, in that if I close the main form
while my new thread is doing work which involves writing to the main
form, then I get an error about a disposed object.

To fix this, i have added an event, with the aim the main form
subscribes to the event when it is created and unsubscribes as soon as
its closed. This approach however has not fixed the problem. When the
event is raised, it writes to the form using a delegate.

This is an extract from my threading class, I have highlighted the code
that raises the event.

Code Snippet

public class ServerConnection()
{
public Boolean terminate = false;
public Thread t1;

public event DebugConsoleAddItem DebugConsoleAddItemEvent;
public delegate void DebugConsoleAddItem(ServerConnection sc, EventArgs e);
public EventArgs e = null;


public ServerConnection(connection_data cd)
{
// Constructor


mform = cd.mf;


t1 = new Thread(new ThreadStart(BeginWork));
t1.Start();
}


private void BeginWork()
{
ProcessData();
}

private int ProcessData()
{

do
{
if (terminate == true)
{
return -1;
}

if (group_info != ".")
{

group_info = clientStreamReader.ReadLine();

if (DebugConsoleAddItemEvent != null)
{
DebugConsoleAddItemEvent(this, e);
}


}

} while (group_info != ".");
}
}

Now my event Listener class is here, The highlighted line invokes the
delegate in the main form, mform is a reference to the main form passed
to the ServerConnection class above in its constructor.

Code Snippet

public class Listener
{
public void Subscribe(ServerConnection s)
{
s.DebugConsoleAddItemEvent += new
ServerConnection.DebugConsoleAddItem(HeardIt);
}

public void UnSubscribe(ServerConnection s)
{
s.DebugConsoleAddItemEvent -= new
ServerConnection.DebugConsoleAddItem(HeardIt);
}

private void HeardIt(ServerConnection sc, EventArgs e)
{
if (sc.terminate != true)
{
if (sc.terminate != true)
sc.mform.Debug_Console_Add_Item("test");
}
}

}

Now finally in my main form, the relevant code:

Code Snippet

ServerConnection SC;
Listener l = new Listener();

private void MainForm_FormClosing(object sender,
System.Windows.Forms.FormClosingEventArgs e)
{
SC.terminate = true;
l.UnSubscribe(SC);
}

public delegate void UpdateDebugConsoleDelegate(string entry);

public void Debug_Console_Add_Item(string entry)
{

if (this.DebugConsole.InvokeRequired)
{
UpdateDebugConsoleDelegate theDelegate = new
UpdateDebugConsoleDelegate(this.Debug_Console_Add_Item);
this.Invoke(theDelegate, new object[] { entry });
}
else
{


try
{
DebugConsole.Items.Add(entry);
}
catch (Exception e)
{
MessageBox.Show("Error" + e.ToString());
}

}

}


I would really appreciate any help on how to resolve this, I haven't
used events before, but it seems to be working correctly, until i close
the form anyway.

I have a feeling the problem is down to the way I use the mform
reference, but i don't know how to do it correctly.

EDIT: For some reason the while loop in the thread does not detect the
change in the termination flag to true before the object is disposed,
however if i put a Thread.Sleep(200) in there, then it picks it up and
does not try to write to the disposed object, but obviously this is not
a solution.

Thanks for any help,
Jason
 
C

colin

JasonX said:
Im having problems with my program, in that if I close the main form while
my new thread is doing work which involves writing to the main form, then
I get an error about a disposed object.
[...]

I had similar problem, I had to make the main form thread wait for the new
thread to finish.
you can do this in the Close function and you also need to call the main
message pump while waiting in a loop.
obviously you have to signal to the new thread that it should finish.

However I since did it all another way and I dont seem to have a copy of the
code.

Colin =^.^=
 
B

Bruce Wood

Why not just do this?

public void Debug_Console_Add_Item(string entry)
{
if (!this.IsDisposed)
{
if (this.DebugConsole.InvokeRequired)
{
UpdateDebugConsoleDelegate theDelegate = new
UpdateDebugConsoleDelegate(this.Debug_Console_Add_Item);
this.Invoke(theDelegate, new object[] { entry });
}
else
{
try
{
DebugConsole.Items.Add(entry);
}
catch (Exception e)
{
MessageBox.Show("Error" + e.ToString());
}
}
}
}

That way, if the form is disposed, the callback won't happen, or, if
it has already happened, it won't do anything.

By the way, you shouldn't code

if (xxx != true)

IMHO it looks clunky. Better to write

if (!xxx)

instead. :)
 
R

Ranjeet Bhargava

u shud set CheckForIllegalCroossThreadCalls =false
bool Property of tht Control (in which u using Class
as Windows.form etc.)

Happy Coding!!


EggHeadCafe.com - .NET Developer Portal of Choice
http://www.eggheadcafe.com
 
J

Jon Skeet [C# MVP]

u shud set CheckForIllegalCroossThreadCalls =false
bool Property of tht Control (in which u using Class
as Windows.form etc.)

Happy Coding!!

No, that's *not* the solution at all. That's like telling the compiler
not to produce any warnings, just because you can't be bothered to fix
the code.
 
M

Marc Gravell

And just to compund things, the statement is incorrect too:
"...bool Property of tht Control..."
It is of course a *static* property common to *all* Control
instances - hence you would be changing this property for every form
in your AppDomain.

Marc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top