Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#打印和穿线_C#_Multithreading_Printing - Fatal编程技术网

C#打印和穿线

C#打印和穿线,c#,multithreading,printing,C#,Multithreading,Printing,我需要用户能够扫描一系列项目,并为每个项目打印x个标签。我目前正试图使用后台工作人员来完成这项工作,但我遇到了一个问题,他们扫描项目的速度太快,后台工作人员阻塞的每个项目都有太多的标签要打印。这就是我为每次扫描生成后台工作线程的方式,因为在打印大量标签时发生了争用 private void RunPrintWorker() { if (printWorker.IsBusy) { printWorker = new Backgrou

我需要用户能够扫描一系列项目,并为每个项目打印x个标签。我目前正试图使用后台工作人员来完成这项工作,但我遇到了一个问题,他们扫描项目的速度太快,后台工作人员阻塞的每个项目都有太多的标签要打印。这就是我为每次扫描生成后台工作线程的方式,因为在打印大量标签时发生了争用

 private void RunPrintWorker()
    {
        if (printWorker.IsBusy)
        {
            printWorker = new BackgroundWorker();
            printWorker.DoWork += new DoWorkEventHandler(printWorker_DoWork);
            printWorker.RunWorkerAsync();
        }
        else
            printWorker.RunWorkerAsync();
    }
我没有从后台工作人员那里得到任何异常,它只是似乎没有足够快地创建线程。我使用多线程比较新,所以有人能告诉我我做错了什么吗

谢谢

编辑:谢谢大家的建议和阅读材料,这真的很有帮助。标签的打印顺序并不重要,因为它们扫描速度非常快,而且标签也只打印到一台打印机上。我将在实现启动并运行后标记一个答案

编辑:奥斯汀,下面是我如何设置打印方法的。在我调用RunPrintWorker方法中的LabelPrinter.PrintLabels之前。现在我正在重做这个,我不知道要传递什么到SizeQueue方法中。我应该将新创建的打印文档传递给它吗

 public class LabelPrinter
{
    private int CurrentCount = 0;

    private List<int> _selectedRows = new List<int>();
    public List<int> SelectedRows
    {
        get { return _selectedRows; }
        set { _selectedRows = value; }
    }

    private string _selectedTemplate;
    public string SelectedTemplate
    {
        get { return _selectedTemplate; }
        set { _selectedTemplate = value; }
    }

    private string _templateDirectory = string.Empty;
    public string TemplateDirectory
    {
        get { return _templateDirectory; }
        set { _templateDirectory = value; }
    }

    public void PrintLabels(PrintDocument printDoc, PageSettings pgSettings, PrinterSettings printerSettings, List<int> selectedRows, string selectedTemplate, string templateDir)
    {
        this._selectedRows = selectedRows;
        this._selectedTemplate = selectedTemplate;
        this._templateDirectory = templateDir;

        printDoc.DefaultPageSettings = pgSettings;
        printDoc.PrinterSettings = printerSettings;

        printDoc.PrinterSettings.MaximumPage = selectedRows.Count();
        printDoc.DefaultPageSettings.PrinterSettings.ToPage = selectedRows.Count();
        printDoc.PrinterSettings.FromPage = 1;

        printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage);

        printDoc.Print();
    }

    private void printDoc_PrintPage(object sender, PrintPageEventArgs e)
    {
        CurrentCount = DrawLabel.DrawLabelsForPrinting(e, SelectedTemplate, SelectedRows, CurrentCount, TemplateDirectory);
    }
}
公共类标签打印机
{
私有int CurrentCount=0;
私有列表_selectedRows=新列表();
公共列表选定的行
{
获取{return\u selectedRows;}
设置{u selectedRows=value;}
}
私有字符串_selectedTemplate;
公共字符串SelectedTemplate
{
获取{return\u selectedTemplate;}
设置{u selectedTemplate=value;}
}
私有字符串_templateDirectory=string.Empty;
公共字符串模板目录
{
获取{return\u templateddirectory;}
设置{u templateDirectory=value;}
}
公共无效打印标签(打印文档打印文档、页面设置、页面设置、打印设置、打印设置、列表选择的箭头、字符串选择的模板、字符串模板目录)
{
这。\ u selectedRows=selectedRows;
这.\u selectedTemplate=selectedTemplate;
这是._templateDirectory=templateDir;
printDoc.DefaultPageSettings=pgSettings;
printDoc.PrinterSettings=PrinterSettings;
printDoc.PrinterSettings.MaximumPage=selectedRows.Count();
printDoc.DefaultPageSettings.PrinterSettings.ToPage=selectedRows.Count();
printDoc.PrinterSettings.FromPage=1;
printDoc.PrintPage+=新的PrintPageEventHandler(printDoc\u PrintPage);
printDoc.Print();
}
私有void printDoc_PrintPage(对象发送方,PrintPageEventArgs e)
{
CurrentCount=DrawLabel.DrawLabels用于打印(e,SelectedTemplate,SelectedRows,CurrentCount,TemplateDirectory);
}
}

尝试将项目添加到队列中(例如,
队列
),并让BackgroundWorker处理该队列

编辑:添加一些简单、未经测试、可能适合您的代码。我会用它的处理器封装打印队列,然后只发送作业给它

class SimpleLabelPrinter
{
    public bool KeepProcessing { get; set; }
    public IPrinter Printer { get; set; }

    public SimpleLabelPrinter(IPrinter printer)
    {
        Printer = printer;
    }


    /* For thread-safety use the SizeQueue from Marc Gravell (SO #5030228) */        
    SizeQueue<string> printQueue = new SizeQueue<string>();

    public void AddPrintItem(string item)
    {
        printQueue.Enqueue(item);
    }

    public void ProcessQueue()
    {
        KeepProcessing = true;

        while (KeepProcessing)
        {
            while (printQueue.Count > 0)
            {
                Printer.Print(printQueue.Dequeue());
            }

            Thread.CurrentThread.Join(2 * 1000); //2 secs
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        SimpleLabelPrinter printer1 = new SimpleLabelPrinter(...);
        SimpleLabelPrinter printer2 = new SimpleLabelPrinter(...);

        Thread printer1Thread = new Thread(printer1.ProcessQueue);
        Thread printer2Thread = new Thread(printer2.ProcessQueue);

        //...

        printer1.KeepProcessing = false;  //let the thread run its course...
        printer2.KeepProcessing = false;  //let the thread run its course...
    }
}

您需要实现一个排队系统。看看Queue类,并在其中对打印文档进行排队。启动一个后台线程(在这种情况下不是backgroundworker),让它定期检查队列中的更多项目,如果可以的话,打印它们

在backgroundworker中运行如下方法:

private void PrintLoop()
{
    while (true)
    {
        if (documents.Count > 0)
        {
            PrintDocument document = documents.Dequeue();
            document.Print();

        }
        else
        {
            Thread.Sleep(1000);
        }
    }
}

为每台打印机创建一个BackgroundWorker,并将每个打印到不同的打印机。

基本上,您要做的是,如果打印机忙,请使用另一个worker覆盖您的printWorker对象,然后启动该对象。然后,就没有对旧辅助对象的引用,也不进行任何清理

这里面有各种各样的问题

  • 后台工作人员必须在完成后进行处理,以防止泄漏
  • 创建更多的后台工作并不意味着打印机将运行得更快,它只是意味着有更多的工人试图同时到达打印机
你需要做的是考虑排队。我想说你有两个主要的选择

首次使用

这将使用.net线程池对任务进行排队并在池中处理它们。(池将自动调整为适当数量的线程,以处理排队的请求)。这不需要处理或清理,您只需启动并忘记,尽管您需要注意,工作项不能保证按照添加它们的相同顺序进行处理(可能有些工作项会同时处理),因此如果您关心顺序,这是不好的

第二,实施计划。这需要一个同步队列,其中一个或多个线程(生产者)向其中添加项目,而其他线程(消费者)删除并处理这些项目。如果您是线程新手,这可能会非常棘手,因为您必须确保对共享队列的读/写正确同步,以便保持顺序,并且不会丢失任何内容

注意类型,尽管可以使用它,但它本身并不是自动线程安全的。如果您确实使用它,请确保您添加了一些自己的锁定和同步功能

从MSDN页面:

任何实例成员都不能保证线程安全

队列)可以同时支持多个读卡器,只要不修改集合。即便如此,通过集合枚举本质上并不是线程安全的过程。为了保证枚举期间的线程安全,可以在整个枚举期间锁定集合。要允许多个线程访问集合进行读写,必须实现自己的同步

如果您不关心顺序,但如果您发现需要对队列和队列进行更细粒度的控制,我建议您使用更简单的第一个选项
private void PrintLoop()
{
    while (true)
    {
        if (documents.Count > 0)
        {
            PrintDocument document = documents.Dequeue();
            document.Print();

        }
        else
        {
            Thread.Sleep(1000);
        }
    }
}
ThreadPool.QueueUserWorkItem(new WaitCallback(o=>{printWorker_DoWork();}));