|
Architect or Cobbler?
Good code starts with good design |
|
about me
links
Blogs I follow
recent posts
archives
feeds |
Merry Christmas ...Sunday, December 24, 2006To all, and especially my 3 subscribers, whoever you are. And I thought I'd be reaching out to thousands when I started this blog. I hope Santa brings you everything you're after, and I hope he brings me a Wii :-) Although if previous form is anything to go by, it will be a comedy tie, some socks and a book that I bought at the airport 3 weeks ago anyway ;-) So have fun, and to all the geeks out there, put the laptops (or desktops, PDAs or whatever else you use to keep connected) away until after Christmas, which is what I intend to do right now. # posted by James @ 12:40 PM How to use BackgroundWorker properly ;-)Saturday, December 23, 2006Well, I've been looking at the problem a little more carefully, and it is definitely a race condition, however you can avoid it quite simply. First a bit of code that demonstrates the problem more fully. private void button1_Click(object sender, EventArgs e) private void DoWork(object sender, DoWorkEventArgs e) The problem stems from the fact that DoWork is run in a separate thread, so if you have to write to the GUI then you have to marshal it via Invoke. So naturally in my eagerness to improve performance I use BeginInvoke, which simply spawns a thread and then continues. The spawned thread then sleeps for a bit (just to make the race condition more apparent - even without the sleep this code will occasionally fail) writes to a textbox and then reports progress. By the time the ReportProgress call is marshaled to the right thread, the thread has completed as DoWork will have finished. The solution is simple, never use BeginInvoke (or indeed spawning a new thread by any other means) from the DoWork handler, so to fix the code above, just change BeginInvoke to Invoke - it works every time now, and is certainly better than my cludgy sleep I was using earlier :-) # posted by James @ 6:14 PM BackgroundWorker race condition bug?As I said the other day, I'm writing a new course (actually updating an existing one), and I've been writing practicals for the delegates. As part of this I wrote an exercise that used BackgroundWorker to spawn a thread that searches for files on the file system. Occasionally the program would fail with a System.InvalidOperationException with the message "This operation has already had OperationCompleted called on it and further calls are illegal." I realised straight away that my call to ReportProgress was causing the ProgressChanged event to be raised after the BackgroundWorker had raised the RunWorkerCompleted event. I suspected my code and banged around for ages trying to find the problem, but it actually appears to be a bug in the implementation. If you raise a ReportProgress at roughly the same time the thread completes, you have a race, and one that the RunWorkerCompleted will nearly always win, as it doesn't have to issue a BeginInvoke. In my case I was reporting progress every 23 files (don't ask it seemed a good number), and in cases where the search returns multiples of 23, then the RunWorkerCompleted would be raised at the same time as the ReportProgress and I'd get a race condition. For now I've added a sleep at the end of my DoWork event handler to prevent it from finishing before my last ReportProgress has been actioned. Does anyone have any better ideas? # posted by James @ 4:29 PM Coming up for airWednesday, December 20, 2006December is always the busiest month for those in the training community, and this month hasn't been any different. I've just come off teaching a graduate program, and as always it was great to be challenged by so many bright, new and confident people. Of course it's meant I've had to go back to basics for a month or so, so I haven't been concentrating on my development during this time. All that changes now, I'm writing new exercises and material for our .Net 3 curriculum, so I'll be sitting down over the next few weeks with Reflector and some coffee trying to really get to grips with WCF, WPF and WF. So I'll probably be blogging about interesting little nuggets as I find them. And of course always bear in mind I get it wrong as often as I get it right. As Rob pointed out in a comment below, WPF windows should only have one Menu attached and then you should use child MenuItem structures to arrange the Menus. I've fixed my copy of Scribble and you can download it here OK, I'm off to play with SafeHandles now. # posted by James @ 12:37 PM |
|
|
|