0

我想从我的 dot net 项目作为后台工作作为线程进行打印,为此我所做的是,首先将每个输出字符串收集到这样的字符串集合中:

 myOutputStringCollection.Add(str);

然后在收集了我想将它发送到打印机的所有行之后,我编写了这样的代码来执行一个线程:

public static void printAllLines()
{
    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].ToString());
     }

     Array.Clear(myArray, 0, myArray.Length);
 }

这里面临的问题是,如果我立即单击打印按钮不止一次,那么打印对齐不正确,我认为如果我正确处理线程执行,那就没问题了。

4

4 回答 4

2

为了防止发生此问题,我会在启动线程之前禁用打印按钮,然后在将字符串发送到打印机后重新启用它:

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;
    }));     
}

不需要调用 Array.Clear(),因为 myArray 是一个局部变量,因此在 sendToPrinter 方法(和线程)结束时无论如何都会被销毁。

于 2013-05-20T12:16:13.120 回答
1

根据桑迪的回答,禁用按钮是一回事。最重要的是,您应该锁定 SendStringToPrinter,因此当时只有一个线程正在访问它。简单的例子:

lock (lockObj)
{
    SendStringToPrinter(myArray[i].ToString());
}

lockObj 应该是一个不可变对象。以下内容应该适合您:

private static readonly object lockObj = new object();

阅读更多http://msdn.microsoft.com/en-us/library/c5kehkcz(v=vs.71).aspx

于 2013-05-20T13:34:39.633 回答
0

作为您问题的直接解决方案,您需要同步对共享资源(myOutputStringCollection字段)的访问:

将字符串添加到集合的位置:

lock(myOutputStringCollection)
{
    myOutputStringCollection.Add(str);
}

然后该sendToPrinter方法应如下所示:

public static void sendToPrinter()
{
    string[] myArray;

    lock(myOutputStringCollection)
    {
        myArray = myOutputStringCollection.ToArray();
        myOutputStringCollection.Clear();
    }

    for (int i = 0; i < myArray.Length; i++)
    {
        SendStringToPrinter(myArray[i]);
    }
}

但是要拥有一个“正确的”和(稍微更高级的)解决方案,您应该考虑实施生产者/消费者设计模式。我建议使用数据流实现(如果是新开发)

于 2013-05-20T13:35:54.843 回答
0

我认为您必须等待所有正在运行的线程完成它们的工作然后清除数组,即使您不需要完全清除数组。

另一点,您的数组可能会非常冗长,并且创建这么多线程肯定是低效的。

在后一种情况下,您可以考虑线程池。

于 2013-05-20T12:18:26.247 回答