Reputation: 3046
I want to do the printing from my dot net project as background work as a thread, for that what I did is, first collect the each output string to a collection of string like this:
myOutputStringCollection.Add(str);
Then after collecting all lines I want to send it to printer, I write code like this which executes a thread:
public static void printAllLines()
{
Thread t = new Thread(sendToPrinter);
t.Start(); //starts the thread
}
and the send to printer function is like this:
public static void sendToPrinter()
{
int count = myOutputStringCollection.Count;
string[] myArray = new string[count];
myOutputStringCollection.CopyTo(myArray, 0);
for (int i = 0; i < count; i++)
{
SendStringToPrinter(myArray[i].ToString());
}
Array.Clear(myArray, 0, myArray.Length);
}
The problem here am facing is, if I click the print button more than one times Immediately then the printing alignment is not correct, I think if I handle the thread execution properly then it will be all right.
Upvotes: 0
Views: 1813
Reputation: 1832
As a direct solution to you problem you need to synchronise the access to you shared resource (the myOutputStringCollection
field):
Where you add the strings to the collection:
lock(myOutputStringCollection)
{
myOutputStringCollection.Add(str);
}
An then the sendToPrinter
method should look like this:
public static void sendToPrinter()
{
string[] myArray;
lock(myOutputStringCollection)
{
myArray = myOutputStringCollection.ToArray();
myOutputStringCollection.Clear();
}
for (int i = 0; i < myArray.Length; i++)
{
SendStringToPrinter(myArray[i]);
}
}
But to have a "correct" and (slightly more advanced) solution you should think of implementing a producer/consumer design pattern. I would suggest using a dataflow implementation (if it is new development)
Upvotes: 0
Reputation: 14496
As per Sandy's answer, disabling a button is one thing to do. On top of that, you should put a locking around SendStringToPrinter, so only one thread at the time is accessing that. Simple example:
lock (lockObj)
{
SendStringToPrinter(myArray[i].ToString());
}
lockObj should be an immutable object. The following should work for you:
private static readonly object lockObj = new object();
Read more on http://msdn.microsoft.com/en-us/library/c5kehkcz(v=vs.71).aspx
Upvotes: 1
Reputation: 14874
I think you must wait for all running threads to finish their work then Clear the array even though you don't need to Clear the array altogether.
Another point, chances are your array would be very lengthy and creating so many threads is definitely inefficient.
You can think about thread pools in the latter case.
Upvotes: 0
Reputation: 3046
To prevent this problem from occurring, I'd disable the print button just before you start the thread and then re-enable it after the strings have been sent to the printer:
public static void printAllLines()
{
btnPrint.Enabled = false;
Thread t = new Thread(sendToPrinter);
t.Start();//starts the thread
}
public static void sendToPrinter()
{
int count = myOutputStringCollection.Count;
string[] myArray = new string[count];
myOutputStringCollection.CopyTo(myArray, 0);
for (int i = 0; i < count; i++)
{
SendStringToPrinter(myArray[i]); // no need for ToString() as it's already a string
}
// re-enable print button by marshalling to UI thread
this.Invoke(new MethodInvoker(delegate()
{
btnPrint.Enabled = true;
}));
}
The call to Array.Clear() shouldn't be needed as myArray is a local variable and will therefore be destroyed anyway when the sendToPrinter method (and the thread) ends.
Upvotes: 2