大家好,我最近将一个大型应用程序多线程化后,遇到了并发问题。问题出在可以运行批处理作业的脚本处理器中。
public async Task<Result> ProcessScriptAsync(
CancellationTokenSource cancelSource,
TaskScheduler uiScheduler)
{
...
// Get instance of active workbook on UI thread.
IWorkbook workbook = this.workbookView.ActiveWorkbook;
while (notFinished)
{
...
Task<bool> runScriptAsyncTask = null;
runScriptAsyncTask = Task.Factory.StartNew<bool>(() =>
{
return RunScript(ref workbook);
}, this.token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
// Some cancellation support here...
// Run core asynchroniously.
try
{
bGenerationSuccess = await runScriptAsyncTask;
}
catch (OperationCanceledException)
{
// Handle cancellation.
}
finally
{
// Clean up.
}
}
...
}
当考虑到RunScript
方法时,我的问题出现了。传递给RunScript
的对象不是线程安全的,并且是在UI线程上创建的。因此,在RunScript
方法内部我必须创建该对象的“深拷贝”...
private bool RunScript(ref IWorkbook workbook)
{
...
// Get a new 'shadow' workbook with which to operate on from a background thread.
IWorkbook shadowWorkbook;
if (File.Exists(workbook.FullName))
{
// This opens a workbook from disk. The Factory.GetWorkbook method is thread safe.
shadowWorkbook = SpreadsheetGear.Factory.GetWorkbook(workbook.FullName); // (##)
}
else
throw new FileNotFoundException(
"The current workbook is not saved to disk. This is a requirement. " +
"To facilitate multi-threading!");
// Do hard work here...
shadowWorkbook.WorkbookSet.GetLock();
try
{
// Do work and add worksheets to shadowWorkbook.
}
finally
{
// Reassign the UI workbook object to our new shadowWorkbook which
// has been worked on. This is fine to do as not work is actually being
// done on workbook.
workbook = shadowWorkbook;
shadowWorkbook.WorkbookSet.ReleaseLock();
}
}
我的问题出现在(##)标记的行上。每次执行
RunScript
时,都会从磁盘创建一个新的shadowWorkbook
。问题是,在shadowWorkbook
中创建了一些工作表,随后将这些工作表复制回workbook
进行处理。但是,每次执行RunScript
时,我都会从磁盘获取workbook
,其中没有生成在最后一个循环中的新工作表。我尝试将
shadowWorkbook
设为全局对象,但它是在UI线程上创建的,因此不能从后台操作中使用。解决这个问题的方法之一是在每个工作表创建后将工作簿保存到磁盘,但这样做会很耗费资源。
是否有一种方法可以使shadowWorkbook
成为全局变量并且线程安全,以便能够跨线程调用保留对我的IWorkbook
进行更改?
感谢你的时间。