使用多线程使用 iTextSharp 生成 Datamatrix 会导致崩溃
Generating Datamatrix with iTextSharp using multithreading causes crash
在为标签生成数据矩阵时,我的代码发生崩溃。经过大量测试,我确定这是由于多线程造成的,但我无法确定原因。
我正在使用 iTextSharp v5.5.13.2(Nuget 包)。将复制错误的代码如下:
for(int i = 0; i < 10; i++)
{
ThreadPool.QueueUserWorkItem(x =>
{
iTextSharp.text.pdf.BarcodeDatamatrix dataMatrix = new iTextSharp.text.pdf.BarcodeDatamatrix();
dataMatrix.Height = 18;
dataMatrix.Width = 18;
dataMatrix.ForceSquareSize = true;
dataMatrix.Generate("TestData");
});
Console.WriteLine(i);
}
这是错误:
System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'
This exception was originally thrown at this call stack:
iTextSharp.text.pdf.BarcodeDatamatrix.B256Encodation(byte[], int, int, byte[], int, int, int, int, int)
iTextSharp.text.pdf.BarcodeDatamatrix.GetEncodation(byte[], int, int, byte[], int, int, int, bool)
iTextSharp.text.pdf.BarcodeDatamatrix.Generate(byte[], int, int)
iTextSharp.text.pdf.BarcodeDatamatrix.Generate(string)
DataAccessTesting.Form1.Function1_Click.AnonymousMethod__59_0(object) in Form1.cs
System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(object)
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, object, bool)
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, object, bool)
System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
System.Threading.ThreadPoolWorkQueue.Dispatch()
...
[Call Stack Truncated]
如果我删除多线程,它运行得很好。所以这段代码有效:
for (int i = 0; i < 10; i++)
{
iTextSharp.text.pdf.BarcodeDatamatrix dataMatrix = new iTextSharp.text.pdf.BarcodeDatamatrix();
dataMatrix.Height = 18;
dataMatrix.Width = 18;
dataMatrix.ForceSquareSize = true;
dataMatrix.Generate("TestData");
Console.WriteLine(i);
}
我在应用程序中使用多线程来生成所有标签并立即开始打印它们,即使其他标签仍在生成。强迫它们等待其他每个都完成处理会显着降低应用程序的速度,因此删除多线程是不得已的选择。
如何在不删除多线程的情况下防止发生此错误?
编辑:
我一直被告知我没有完整的代码。我再次测试,通过将我添加的代码放入按钮事件中,我可以复制错误。这是一个截图。
反编译库中的 BarcodeDatamatrix
确认 Generate
方法不是线程安全的,因为使用了以下字段(感谢@Enigmativity 的洞察力评论):
private static int[][] f;
private static int[][] switchMode;
以下位置的 class 使这些字段(以及使用它们的其他方法)不是 static
,修复了线程安全问题。重要提示:如果 library/NuGet(实际上是这个 class)得到更新,如果您想使用最新版本,可能需要再次执行此操作:
https://pastebin.com/PFnqBYQa
备选方案
使用可用的 DataMatrix.net
库 here or here(旧库,不确定哪个更好)。
附加信息
我还测试了 ZXing.NET 但 FNC1 字符(例如组分隔符 \x1D
)无法正常工作。这适用于上述库。
代码示例(用于替代库):
// ZXING: FNC1 not working
//var dm = new BarcodeWriter
//{
// Format = BarcodeFormat.DATA_MATRIX,
// Options =
// {
// GS1Format = true,
// PureBarcode = true
// }
//};
//var gs1Code = "0107612345678900171" + "\x1D" + "00503";
//var bmp = dm.Write(gs1Code);
//return bmp;
// Datamatrix.NET
var imageEncoder = new DmtxImageEncoder();
var options = new DmtxImageEncoderOptions
{
ModuleSize = 8,
MarginSize = 30,
BackColor = Color.White,
ForeColor = Color.Black,
Scheme = DmtxScheme.DmtxSchemeAsciiGS1
};
var barcode = txt1.Text.Length == 13
? "0" + txt1.Text
: txt1.Text;
return imageEncoder.EncodeImage("01" + barcode
+ "10" + txt2.Text + "\x1D"
+ "21" + txt3.Text
, options);
在为标签生成数据矩阵时,我的代码发生崩溃。经过大量测试,我确定这是由于多线程造成的,但我无法确定原因。
我正在使用 iTextSharp v5.5.13.2(Nuget 包)。将复制错误的代码如下:
for(int i = 0; i < 10; i++)
{
ThreadPool.QueueUserWorkItem(x =>
{
iTextSharp.text.pdf.BarcodeDatamatrix dataMatrix = new iTextSharp.text.pdf.BarcodeDatamatrix();
dataMatrix.Height = 18;
dataMatrix.Width = 18;
dataMatrix.ForceSquareSize = true;
dataMatrix.Generate("TestData");
});
Console.WriteLine(i);
}
这是错误:
System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'
This exception was originally thrown at this call stack:
iTextSharp.text.pdf.BarcodeDatamatrix.B256Encodation(byte[], int, int, byte[], int, int, int, int, int)
iTextSharp.text.pdf.BarcodeDatamatrix.GetEncodation(byte[], int, int, byte[], int, int, int, bool)
iTextSharp.text.pdf.BarcodeDatamatrix.Generate(byte[], int, int)
iTextSharp.text.pdf.BarcodeDatamatrix.Generate(string)
DataAccessTesting.Form1.Function1_Click.AnonymousMethod__59_0(object) in Form1.cs
System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(object)
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, object, bool)
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, object, bool)
System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
System.Threading.ThreadPoolWorkQueue.Dispatch()
...
[Call Stack Truncated]
如果我删除多线程,它运行得很好。所以这段代码有效:
for (int i = 0; i < 10; i++)
{
iTextSharp.text.pdf.BarcodeDatamatrix dataMatrix = new iTextSharp.text.pdf.BarcodeDatamatrix();
dataMatrix.Height = 18;
dataMatrix.Width = 18;
dataMatrix.ForceSquareSize = true;
dataMatrix.Generate("TestData");
Console.WriteLine(i);
}
我在应用程序中使用多线程来生成所有标签并立即开始打印它们,即使其他标签仍在生成。强迫它们等待其他每个都完成处理会显着降低应用程序的速度,因此删除多线程是不得已的选择。
如何在不删除多线程的情况下防止发生此错误?
编辑:
我一直被告知我没有完整的代码。我再次测试,通过将我添加的代码放入按钮事件中,我可以复制错误。这是一个截图。
反编译库中的 BarcodeDatamatrix
确认 Generate
方法不是线程安全的,因为使用了以下字段(感谢@Enigmativity 的洞察力评论):
private static int[][] f;
private static int[][] switchMode;
以下位置的 class 使这些字段(以及使用它们的其他方法)不是 static
,修复了线程安全问题。重要提示:如果 library/NuGet(实际上是这个 class)得到更新,如果您想使用最新版本,可能需要再次执行此操作:
https://pastebin.com/PFnqBYQa
备选方案
使用可用的 DataMatrix.net
库 here or here(旧库,不确定哪个更好)。
附加信息
我还测试了 ZXing.NET 但 FNC1 字符(例如组分隔符 \x1D
)无法正常工作。这适用于上述库。
代码示例(用于替代库):
// ZXING: FNC1 not working
//var dm = new BarcodeWriter
//{
// Format = BarcodeFormat.DATA_MATRIX,
// Options =
// {
// GS1Format = true,
// PureBarcode = true
// }
//};
//var gs1Code = "0107612345678900171" + "\x1D" + "00503";
//var bmp = dm.Write(gs1Code);
//return bmp;
// Datamatrix.NET
var imageEncoder = new DmtxImageEncoder();
var options = new DmtxImageEncoderOptions
{
ModuleSize = 8,
MarginSize = 30,
BackColor = Color.White,
ForeColor = Color.Black,
Scheme = DmtxScheme.DmtxSchemeAsciiGS1
};
var barcode = txt1.Text.Length == 13
? "0" + txt1.Text
: txt1.Text;
return imageEncoder.EncodeImage("01" + barcode
+ "10" + txt2.Text + "\x1D"
+ "21" + txt3.Text
, options);