From: Peter Duniho on
David wrote:
> [...]
> (Because my app is for scanning, the gui becomes unresponsive, which is
> fine, as I don't want the users clicking other buttons to try and scan
> something else whilst it is scanning)

IMHO, you should be thinking about fixing that in the future. For now,
it's probably fine. It seems like you have enough other stuff to worry
about. But more generally, an unresponsive UI means more than just the
inability for the user to be able to provide input and should be avoided.

The usual way to do that would be to use a different thread for the
processing, which in this case is the "using" statement and the block
within. And of course, that block winds up creating yet another thread.
You may feel that if the threading is already complicated, adding yet
another thread is just plain unreasonable. :) But in reality, it's the
best approach. It would be good to keep that in mind for future
improvements.

> I noted that yours was inside the Main event, which I understand is for a
> console application.

Your Forms-based application has a Main() _method_ too. It's not just
for console applications. But yes, for that particular example, the
significance of the location of that code is related to the fact that
it's a console application.

> I have never used => and at the moment, I don't understand the queue.Consume
> += (i) => { do action }; (actually, just laying it out like that makes it
> look like an array, so this must be a generics thing, but what does =>
> mean)?

It's not an array nor a generics thing. The => operator is documented here:
http://msdn.microsoft.com/en-us/library/bb397687.aspx

and here:
http://msdn.microsoft.com/en-us/library/bb311046.aspx

In this context, it's a way of representing an anonymous method. Given
a ProducerConsumer instance named "queue", as in the example code, the
following are all equivalent:

void ConsumeHandler(string str)
{
// do stuff
}

void button1_Click(object sender, EventArgs e)
{
using(...)
{
queue.Consume += ConsumeHandler;
}
}

and...

void button1_Click(object sender, EventArgs e)
{
using(...)
{
queue.Consume += delegate(string str)
{
// do stuff
};
}
}

and...

void button1_Click(object sender, EventArgs e)
{
using(...)
{
queue.Consume += (str) =>
{
// do stuff
};
}
}

The latter example is the one I used, mainly for its convenience. I
like the anonymous method because it keeps all the relevant
implementation details together, and I like the lambda expression
because it's a bit shorter, especially since the compiler will infer the
type of the argument "str" for me, so I don't have to type it in the
declaration.

All three versions will work the same however.

> This threading stuff is very frustrating, each time I apply threading, my
> app breaks. I have to undo it and it is still broken, so I fix the problem
> then re-apply threading. It is highlighting other issues, but it is only the
> threading that is highlighting it. It seems like a whole different
> discipline in programming.

Well, every language and framework feature is in some respects "a whole
different discipline". In that sense, yes...threading is too.

On the other hand, as you've seen, while threading is in and of itself a
bit of its own discipline, it's also very good at exposing weaknesses in
one's discipline in other areas. Sloppy coding practices that might
have been "safe enough" in a single-threaded design are revealed in
their deficiencies when one tries to combine them with multi-threaded code.

To some extent, this is the sort of thing that just requires practice.
But getting the threading right will help you get _all_ of your code
right. The problems that threading may be exposing are problems
regardless, and _all_ of your code will be better as you practice and
learn to be more disciplined in the way you write the code, even
independent of any threaded behavior.

Pete