zeko

Greetings.
I have an unusual problem.
I have a printer intensive app, which generates a doc and sends it to laser printer.
Document is generated from a documentClass which is a parameter for another printClass that encapusulates printing logic.
Now print class takes the documentClass as parameter in its constructor, and then creates and starts a thread with a print function.
PrintPage event takes info from parameterClass and generates doc (using printDocument here).
Data is sent to a printer and all is ok.
Problem is that during heavy duty printing memory contamination occurs (my guess).
Doc1 gets generated and sent to printer.
Doc2 gets generated and sent to printer.
Doc1 prints out partially with Doc2 info (which should not occur).
Doc2 prints out ok.
Now private documentClass in printerClass is readonly.
I tried even to lock(this) during on print function.
Nothing helps.
So printerClass gets created, its constructor sets everything up and starts printing in new thread, and this eventualy leads to incorrect result.
Can this be a problem with GarbageCollector or does anybody have a clue
Best regards Zeko...





Re: Windows Forms General Printing and multithreading problem

TaylorMichaelL

It depends on what you mean by "Doc1 prints out partially with Doc2 info". If you mean that pages from Doc1 and Doc2 are printed out interleaven then it is a printer setting. By default the printer will print as soon as it has enough information. You can tell it to wait until the print job is done but this will slow things down.

Printers are shared resources but generally you spool all the printed information into the spooler and then it is sent to the printer automatically. This, again, slows things down but ensures that a long print job doesn't stall smaller print jobs that are ready to print but got into the queue later. In this case the only way the data could be interleaven is if you were doing it in code.

Each of your threads needs its own copy of the documents and printer settings to be printed. They can not be shared. The printer itself will be shared but Windows will ensure that either the entire print job is spooled or not (based on the printer settings). Within a print job if you are getting the documents mixed on the same page then it is probably your code doing it. You need to verify that you aren't sharing data across threads.

If this doesn't help solve your problem then please post a slimmed down version of your printing code and threading code so we can take a better look.

Michael Taylor - 6/12/07

http://p3net.mvps.org





Re: Windows Forms General Printing and multithreading problem

zeko

Here is some sample code...

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Drawing.Printing;
using System.Collections;
using System.Drawing;

namespace TestData
{
public class MyDoc
{
private ArrayList _strings;
public ArrayList strings
{
get
{
return _strings;
}
}
}

public class PrintEngine
{
private Thread _t;
private readonly MyDoc _myDoc;
private System.Drawing.Printing.StandardPrintController _prcntrl;
private PrintDocument _printDocument;
private float _startx = 0;
private float _starty = 0;
private Font _font;

public PrintEngine(MyDoc myDoc)
{
_myDoc = myDoc;
_font = new Font("Arial", 10);
_printDocument = new PrintDocument();
_prcntrl = new System.Drawing.Printing.StandardPrintController();
_printDocument.PrintPage += new PrintPageEventHandler(_printDocument_PrintPage);
_t = new Thread(new ThreadStart(Print));
_t.IsBackground = true; ;
_t.Start();
}

private void Print()
{
lock (this)
{
_printDocument.Print();
}
}

void _printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
float x = _startx;
float y = _starty;
foreach (string s in _myDoc)
{
y += 10;
e.Graphics.DrawString(s, font, Brushes.Black, x, y);
}
}
}

static class Program
{

static void Main()
{
for (int i = 1; i < 6; i++)
{
MyDoc myDoc = new MyDoc();
/*
* Add some data to myDoc
*/
myDoc.strings.Add(string.Format("Document {0}", i));
PrintEngine p = new PrintEngine(myDoc);
/*Prints my doc in new background thread*/

}


}
}
}

The problem is that following can happen:
Document 1 prints with Document 1 on it,
Document 2 prints with Document 2 on it,
* Document 3 prints with Document 4 on it, *
Document 4 prints with Document 4 on it,
Document 5 prints with Document 5 on it






Re: Windows Forms General Printing and multithreading problem

zeko

And I forgot to say that these are all small documents (1 to 2 pages).





Re: Windows Forms General Printing and multithreading problem

zeko

Any news on this





Re: Windows Forms General Printing and multithreading problem

TaylorMichaelL

Sorry for the delay. I missed the e-mail alert.

I wasn't able to reproduce any problem with the code you sent. Each document was printed properly. I sent the data to the XPS Document Writer so I could see the output without having to waste paper. I also modified your code to block until all the threads completed their work. If you didn't do this then the print buffer could easily become corrupt.

Does the problem occur all the time or only occasionally Does it occur on all printers or just a certain one Do you have print spooling enabled on the printer

Michael Taylor - 6/20/07

http://p3net.mvps.org





Re: Windows Forms General Printing and multithreading problem

zeko

Thanx for response.
It happens occasionally on slower machines.
Problem is printer independant. I tried it on samsung and kyocera printers.
Spooling is turned on.
I work for bet-shops which print their recieps on laser printers.
I wanted to speed up the proccess becouse a 2-3 second slowdown can occur if printing is done within same thread.

" I also modified your code to block until all the threads completed their work."
Could you please give me code example of this
Best regards...





Re: Windows Forms General Printing and multithreading problem

TaylorMichaelL

If it happens only on slower machines and sporadically then it could be related to how the pages are being spooled. Since spooling is on the entire document has to be generated and sent to the spooler before it'll print.

I took your original code and modified it like so:

Code Snippet

//PrintEngine

public void Join ( )

{

_t.Join();

}

//Main

Collection engines = new ...;

for (...)

{

PrintEngine eng = new ...;

engines.Add(eng);

...

};

//Later on

foreach(PrintEngine eng in engines)

eng.Join();

The problem with the above code is that the Join will block the calling thread so you'd almost have to use a separate thread so the join won't block.

You might find the BackgroundWorker component a better option than using threads. It does basically the same thing as your code except it uses the TP and you know when it is done. It also allows for progress notification and cancellation support. I'd also recommend that you move the thread handling outside the PrintEngine code. In general the caller should be responsible for handling threading. Thus if you wanted to print something directly you'd just do this:

Code Snippet

PrintEngine eng = new ...;

...

eng.Print(); //Blocks until done

However if you wanted to do the work in a secondary thread (i.e TP) then you could just modify the calling infrastructure like so:

Code Snippet

BackgroundWorker bwc = new ...;

bwc.DoWork += PrintStuff;

bwc.RunWorkerAsync();

private void PrintStuff ( )
{

PrintEngine eng = new ...;

...

eng.Print();
}

Here is a link to an article on how to use BWC: http://p3net.mvps.org/Topics/WinForms/BackgroundWorker.aspx The article is based around having a UI but this is not required. BWC works in any application.

A final option I'll lay down is to use only a single thread (or BWC) and create a print manager class. You can then basically send it a list of documents and it'll print each one in turn. Sort of like a print queue. Assuming that all documents are going to the same printer then the performance will be identical whereas the resource usage will be low. Performance wise the code will execute faster than the printer can run anyway.

Michael Taylor - 6/22/07

http://p3net.mvps.org





Re: Windows Forms General Printing and multithreading problem

zeko

Thank you very much. This was very helpful.