使用c#,。NET Framework 4.5,VS 2012
尝试使用Parallel.Foreach
结果有一些UI和按钮的添加方法(方法允许旋转文件夹中的所有图片并保存在另一个地方)
private void ProcessFileParallel()
{
string[] files =
Directory.GetFiles(@"C:\Users\Public\Pictures\Sample Pictures",
"*.jpg", SearchOption.AllDirectories); //get source folder
string dirNew = @"C:\modifiedImages"; //new folder
Directory.CreateDirectory(dirNew); //create dir
//usage of parallel and lambda
Parallel.ForEach(files, currfiles =>
{
string fileName = Path.GetFileName(currfiles); //get cur name of file
//GC for Bitmap
//create new object of Bitmap
using (Bitmap bitmap = new Bitmap(currfiles))
{
bitmap.RotateFlip(RotateFlipType.Rotate180FlipX); //rotating
bitmap.Save(Path.Combine(dirNew, fileName)); //save as
//anonym delegate - used for safety access to UI elements from secondary thread
this.Invoke((Action)delegate
{
//caption name change for form
this.Text =
string.Format("Curr Thread {0}",
Thread.CurrentThread.ManagedThreadId);
}
);
}
}
);
}
它的工作,但结束后(当所有图片旋转并保存在新的地方,并且UI达到顶部类似Curr Thread 11
)主线程被锁定 - 意味着UI未激活 - 无法做任何事情。
问题 - 如何解锁我的UI元素?
答案 0 :(得分:3)
Parallel.ForEach
阻塞线程,直到所有循环完成。如果您希望UI保持响应,则需要在任务中运行它。另见这个问题,基本相同:
答案 1 :(得分:1)
我开始撰写评论,但很快就变得太长了。
首先,我同意ChrisK的答案确实是解决问题的好方法。然而,作为一项学术活动,我认为值得解释为什么问题首先发生。
Parallel.ForEach
阻止调用它的线程(在你的情况下是UI线程),直到所有并行操作完成。与此同时,你有其他线程尝试同步调用UI线程上的操作(已经被阻止)。那些调用必须等待UI线程解除阻塞,但是在所有非UI线程完成工作之前它不会解除阻塞(他们不能,因为他们正在等待)。将军。你有一个僵局,你对Parallel.ForEach
的号召永远不会完成。
实际上,您可以通过简单地将this.Invoke
替换为this.BeginInvoke
来解决您的问题,Parallel.ForEach
会异步地将工作发布到UI线程,从而允许非UI线程继续前进并最终完成;但是我确实认为通过Task
(正如ChrisK所建议的)将对Thread.CurrentThread.ManagedThreadId
的实际调用卸载到线程池是一个更好的解决方案。
P.S。在一个不相关的注释中,您始终在UI线程上调用Thread.CurrentThread.ManagedThreadId
,因此将始终返回您的UI线程的ID ,这可能是也可能不是执行该线程的线程在图像上工作。如果你想知道哪个实际线程正在进行工作,你必须将{{1}}的返回值存储在委托定义之外,然后关闭它。