Re: [2005] threading problem
Yeah, if you pause the UI thread waiting for another thread to finish, then the UI will pause, which means no screen updates. A better solution would be to have the thread raise an event in the UI thread when the datatable is ready. The UI thread would then handle the event to know when it was safe to continue. If invoking a control is an option, you could go that route. Otherwise, raising an event on a different thread is easy to do, but strangely hard to find documentation for it. If that sounds like what you want to do, you could search this forum for SynchronizationContext. I posted a solution to this problem, and I believe I explained the necessary steps, which are few. Frankly, the solution, while easy, feels hokey to me, but I have tested it extensively, and it works nicely.
As for the first thing, it sounds like the connection isn't closing. There are a couple options you might consider, including leaving the connection open, since you apparently use it repeatedly in short order, as well as checking the state of the connection and using it if it is still open. Why it would be still open I can't say, but you did allude to the fact that the code you posted is trimmed for presentation.
Re: [2005] threading problem
It looks like the calls on the different threads are trying to access the same connection. If that's the case, I assume you're using some type of static/singleton (whatever the hell it's called) object for your db access.
Just give it the ThreadStatic Attribute and the app will create one instance for each thread rather than just use the same instance for all the threads and this will avoid that problem.
Re: [2005] threading problem
Well I'm thinking just leaving the connection open sounds like the best idea lol. Can't believe I didn't think of that. In fact you hit Start and my program database IO for like 3 minutes and then it's done and that's it. So i should probably just open the connection at the beginning and close it at the end of the program :P
EDIT: lol I took out the open and close connection command in every loop and now it's over 5x faster
But of course I just realized an even worse problem. No matter how I fix it, in one loop every update command needs to finish completely before the next one or the whole thing will explode cuz the database won't accept it. So I still can't let the program continue until that thread is done. Actually if I fix it so the entire thing event based, that would fix it 100% and it would be perfect and also run as fast as possible. But of course I'd have to re-write my entire program from linear with loops to threads calling each other through events. And it's a massive program so I don't have time before the deadline :(
You know, all I want to do is get the stupid label to refresh. And it's way too much of a hasle to move the other 95% of my code into another thread just to let one stupid label say something. That's why I came up with another tricky idea I wanted to run past you guys. Could I make a new sub and give it its own thread and inside the sub instantiate a small, borderless form on top of my existing form where the label control would be and have a label control inside that new form display the progress data (like "Importing record 5 of 109")? If that would even work, I could just make the string that it should display a module level variable and the thread should be able to access it, right? I might just try that. Btw I'm doing it all with a 2nd form because if I try to access a control on the existing form from another thread...
"Cross-thread operation not valid: Control 'lblStatus' accessed from a thread other than the thread it was created on."
yeah blah blah blah, access it anyway, it's in the same assembly you stupid debugger.
Re: [2005] threading problem
Does the 5x increase change the basic question? If you were to refresh the form after every update, the label would get updated that often, which with the faster execution might be fast enough?
Re: [2005] threading problem
funny you should mention that cuz now that it doesn't have to waste like 80% of the processing cycles on opening and closing the connection, I can't get the label to freeze up :p but of course that's on my supercomputer. I bet if I tried it on a slower one, it'd still have the same problem.
Btw I extensively tested the form on top another form theory and it turns out if you declare the form module level and then as new and .show it the first time through the new sub/thread is called and then every other time just update the label control the new form contains, it crashes because apparently every time the thread/sub is called, it's a new thread and can't access the form it made the first time :( I could declare and open and place a new form every time with an updated label but I don't think anyone's computer is fast enough to render that. Apparently mine's not.
Isn't there just a way to give my stupid original label control permissions so that every thread can access it? I tried changing its modifiers to public which I thought means threads that aren't even in the same assembly can alter its properties but I guess not cuz it didn't work
Re: [2005] threading problem
Quote:
Originally Posted by Desolator144
Isn't there just a way to give my stupid original label control permissions so that every thread can access it? I tried changing its modifiers to public which I thought means threads that aren't even in the same assembly can alter its properties but I guess not cuz it didn't work
Do you mean the "Cross-thread operation not valid: Control '<name>' accessed from a thread other than the thread it was created on" exception that you get when you try and change the value of a control on your form from a worker thread?
I just put a try-catch block around where I update that control and ignore the exception. It seems like it could have some use for large, multi-threaded applications, but when you just want to update a label or something, it's kind of overkill to worry about it. There is some way to code the update to the label in a thread-safe manner, but it just seems to be overly complex for something as basic as this when you know that there's no issue in updating the label.
Re: [2005] threading problem
wait, you're telling me it raises the error in VS but still actually runs the command anyway in the real world? I thought if I let it out that way as soon as it tried to access the control, the computer would blue screen.
Re: [2005] threading problem
I believe to change a control, which is in the UI thread, from any other thread, you use Invoke. I think Atheist posted an example in the last few days. I have always been raising events from background threads, and none of them have ever had to alter a control directly, so I've never tried it.
Theoretically, you can have a single object and let all threads access it willy-nilly. It's almost certainly a bad idea, and in many instances will lead to crashes that are too inconsistent to be positively classified, which makes them a nightmare to debug. However, since you can alter a different object by multiple threads, why not a control? Somebody might know the answer to this, but it sounds like Tom Sawyer is saying that he does just that. Perhaps the label text can be changed, but that change triggers an event (Paint) which, coming from the wrong thread, causes the exception. The change still takes place, because the exception comes from something else.
Re: [2005] threading problem
well this kinda sucks now cuz I can't tell when a slower computer would render it or not without actually putting the program on a slower computer. But I've been thinking and me.refresh() basically tells the form that its graphical status is invalid and it should redraw everything whenever it feels like it. But if I put me.refresh() followed by me.update() that would work, right? Update says it "causes the control to redraw its invalidated client area" So I think that'd be like the "yeah and do it now" that it needs to actually refresh it. I remember using update for something once, probably my timer program, and it actually worked. What do you guys think? Is that a decent fix?
actually shouldn't I be doing:
lblStatus.Refresh()
lblStatus.Update()
hey I tried replacing all the commands with that and it really, really worked cuz the rest of the form was frozen and had chunks missing out of it when I came back but the label kept updating. Hurray! Now time to change it back to form-wide lol
Re: [2005] threading problem
I think Me.Refresh invalidates the entire client area, so that Me.Update is unnecessary. I've used Me.Refresh in several programs to deal with situations similar to what I think you are describing, and it has always been sufficient.
How much difference do you think there is between the two computers? Is the primary computer REALLY fast, as in multiple times as fast as the slower one? If not, I wouldn't expect much difference. This isn't an FPS, where frame rates of 30 fps or better are needed. The screen is re-drawing only a small area, and it will be a very minor drawing operation compared to any 3D game....unless this is a 3D game. You would have to test, but if it works well on a great computer, I would expect it to work fine on a pretty fair computer, as well.
Re: [2005] threading problem
nopers, just a database program. Takes XML from a website of ppl who signed up and sticks em in an Access DB. But the speed it's going now it loops about 50 times per second so that's almost the screen's refresh rate in label refreshes. So hopefully another computer can render that. Mine's a 4400+ X2 and this could be run on just about anything. Mostly old, slow laptops in the field.
Now I figure that the label's text change event invalidates the graphics so if I don't do a me.refresh to invalidate everything, I can just do a me.update and it will only redraw the label and anything else that's been invalidated which should be more efficient. I'll have to try that later
Re: [2005] threading problem
Quote:
Originally Posted by Desolator144
wait, you're telling me it raises the error in VS but still actually runs the command anyway in the real world? I thought if I let it out that way as soon as it tried to access the control, the computer would blue screen.
No, it crashes the program both in VS and in the real world. What I'm saying is that it's an irrelevant error. There are, of course, situations where you don't want background threads to be able to have access to your UI but when you just want a worker thread to notify the user that it's done, then this error check is overkill.
What I do is change:
Code:
lblNotify.Text = "Done"
Which raises a threading error because a worker thread is trying to update the form to:
Code:
try
lblNotify.Text = "Done"
catch ex as Exception
end try
There is a way to use an Invoke command to give your thread access to be able to change the text and using try/catch blocks as part of normal processing is, of course, a hack, but it's too much trouble to make the code thread safe for something this basic and mundane.
Re: [2005] threading problem
Quote:
Originally Posted by Tom Sawyer
No, it crashes the program both in VS and in the real world. What I'm saying is that it's an irrelevant error. There are, of course, situations where you don't want background threads to be able to have access to your UI but when you just want a worker thread to notify the user that it's done, then this error check is overkill.
What I do is change:
Code:
lblNotify.Text = "Done"
Which raises a threading error because a worker thread is trying to update the form to:
Code:
try
lblNotify.Text = "Done"
catch ex as Exception
end try
There is a way to use an Invoke command to give your thread access to be able to change the text and using try/catch blocks as part of normal processing is, of course, a hack, but it's too much trouble to make the code thread safe for something this basic and mundane.
Its unnecessary to have exceptions thrown when you can avoid it, as they are resource-hogs.
Heres an example of how to access controls from worker threads:
VB.Net Code:
Private Sub MethodRunningOnAWorkerThread()
ChangeLabel1Text("Hello world")
End Sub
Private Delegate Sub StringDelegate(ByVal str As String)
Private Sub ChangeLabel1Text(ByVal str As String)
If Label1.InvokeRequired Then
Label1.Invoke(New StringDelegate(AddressOf ChangeLabel1Text), str)
Else
Label1.Text = str
End If
End Sub
Re: [2005] threading problem
A worse resource hog than creating and invoking delegates? I gotta figure that that's a wash.
While it's certainly better coding practice to do it that way and ignoring exceptions is bad coding practice in most cases, updating a label from a worker thread to say that it's done something is such a simplistic action that I find it somewhat offensive that they're gone and made it an error. This is especially true when the code worked fine in VB 2003 but then started throwing errors in 2005 when I upgraded it. It annoyed me so much that I made a moral decision to refuse to deal with it. It's just unecessarily complex for such a basic operation and I don't like having to create delegates for such simplistic tasks.
Re: [2005] threading problem
Quote:
Originally Posted by Tom Sawyer
A worse resource hog than creating and invoking delegates? I gotta figure that that's a wash.
While it's certainly better coding practice to do it that way and ignoring exceptions is bad coding practice in most cases, updating a label from a worker thread to say that it's done something is such a simplistic action that I find it somewhat offensive that they're gone and made it an error. This is especially true when the code worked fine in VB 2003 but then started throwing errors in 2005 when I upgraded it. It annoyed me so much that I made a moral decision to refuse to deal with it. It's just unecessarily complex for such a basic operation and I don't like having to create delegates for such simplistic tasks.
If you're agreeing on the fact that catching and ignoring exceptions is a bad practise, then why are you recommending it? I just tried your approach to the problem, but it didnt update my label. Since an exception is thrown, the line isnt executed properly.
Re: [2005] threading problem
I find the invoke process unnecessarily cumbersome, as well, but it may be a necessary evil. So far, I have always avoided it because background threads talked to the UI thread, not to the user, so no user interface changes were needed. I was just raising events from the background thread, which is easier, though not well documented.
Of course, the end result is pretty much the same, since if you have the background thread raise an event on the UI thread, then the UI thread would have to handle the event for it to be meaningful, and handling the event is about the same as the Invoke in the first place.
Re: [2005] threading problem
Quote:
Originally Posted by Shaggy Hiker
I find the invoke process unnecessarily cumbersome, as well, but it may be a necessary evil. So far, I have always avoided it because background threads talked to the UI thread, not to the user, so no user interface changes were needed. I was just raising events from the background thread, which is easier, though not well documented.
Of course, the end result is pretty much the same, since if you have the background thread raise an event on the UI thread, then the UI thread would have to handle the event for it to be meaningful, and handling the event is about the same as the Invoke in the first place.
Yeah I agree that it sometimes can be cumbersome, but you can always create a method that takes a control argument, so you can change the text property for any control..that way you dont need to create one for each control:
VB.Net Code:
Private Sub MethodRunningOnAWorkerThread()
ChangeControlText(Label1, "Hello world")
End Sub
Private Delegate Sub ControlStringDelegate(ByVal ctrl As Control, ByVal str As String)
Private Sub ChangeControlText(ByVal ctrl As Control, ByVal str As String)
If ctrl.InvokeRequired Then
ctrl.Invoke(New ControlStringDelegate(AddressOf ChangeControlText), ctrl, str)
Else
ctrl.Text = str
End If
End Sub
Just make sure the control you're passing into it has a text property.
Re: [2005] threading problem
Quote:
Originally Posted by Atheist
If you're agreeing on the fact that catching and ignoring exceptions is a bad practise, then why are you recommending it? I just tried your approach to the problem, but it didnt update my label. Since an exception is thrown, the line isnt executed properly.
Hey, you're right. It hoses on the .Text fields.
This is weird because it works fine for updating datepickers and enabling buttons (which is how I use it), so I assumed that updating a label would be the same.
It looks like not only was this a poorly thought out, badly implemented and completely unecessary addition to the 2005 framework, but they didn't bother to test it either.
Re: [2005] threading problem
Grr...
It looks like the Form.Activate() acts like the .Text field and throws the error before changing the value instead of like the .Enabled fields which throw the error after changing the value, so I had to go and use the invoke command anyways in order to have my form pop up when the thread was done.
I was hoping to be able to avoid using it in protest of this stupid change.