Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.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#_Task Parallel Library_Deadlock_Invoke - Fatal编程技术网

C# 在工作线程中调用时的任务死锁

C# 在工作线程中调用时的任务死锁,c#,task-parallel-library,deadlock,invoke,C#,Task Parallel Library,Deadlock,Invoke,我有一个windows窗体程序(**VS 2010.NET 4**),可以递归地检测目录中的文件夹和子文件夹,并优化文件。 我通过任务库来实现这一点,并且在progressbar附近有一个显示项目进度的progressbar和一个显示当前文件的标签。 我有一个SetText(stringtext)方法和delegate(delegate void SetTextCallback(stringtext);)用于此目的。当我想在进程结束时显示messagebox时,我认为它是死锁。但是当我不使用ta

我有一个windows窗体程序(**VS 2010.NET 4**),可以递归地检测目录中的文件夹和子文件夹,并优化文件。 我通过任务库来实现这一点,并且在progressbar附近有一个显示项目进度的progressbar和一个显示当前文件的标签。 我有一个SetText(stringtext)方法和delegate(delegate void SetTextCallback(stringtext);)用于此目的。当我想在进程结束时显示messagebox时,我认为它是死锁。但是当我不使用
task.Wait()时在按钮6中,单击它会正常运行,UI不会挂起。
这是我的代码:

    public partial class Form1 : Form
    {


int MaxFileCounter = 0;
    static int FileCounter = 0;

delegate void SetTextCallback(string text);
delegate void SetProgressCallback(int i);

private void button6_Click(object sender, EventArgs e)
{
    Task task = Task.Factory.StartNew(() =>
    {
        editFiles(txtFilePath.Text);
    });

    task.Wait();

    MessageBox.Show("finished");
}

private void editFiles(string directoryPath)
{
    try
    {
        //DirectoryInfo dirInfo = new DirectoryInfo(txtFilePath.Text);
        DirectoryInfo dirInfo = new DirectoryInfo(directoryPath);
        //string[] extensionArray = { ".jpg", ".png", ".gif" ,".jpeg"};
        string[] extensionArray = txtExtensionList.Text.Split(';');
        HashSet<string> allowedExtensions = new HashSet<string>(extensionArray, StringComparer.OrdinalIgnoreCase);

        FileInfo[] files = Array.FindAll(dirInfo.GetFiles(), f => allowedExtensions.Contains(f.Extension));
        writeFiles(files);

        foreach (DirectoryInfo dir in dirInfo.GetDirectories())
        {
            editFiles(dir.FullName);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

private void writeFiles(FileInfo[] files)
{
    try
    {
        foreach (FileInfo fileinfo in files)
        {
            MemoryStream mo;

            using (Image image = Image.FromFile(fileinfo.FullName))
            {

                SetText(fileinfo.FullName);

                FileCounter++;

                SetProgress(FileCounter * 100 / MaxFileCounter);

                mo = (MemoryStream)optimizeImage(image, int.Parse(txtPercent.Text));
            }

            byte[] bt = new byte[mo.Length];
            mo.Read(bt, 0, bt.Length);
            mo.Flush();
            mo.Close();

            string fullpath = fileinfo.FullName;

            File.WriteAllBytes(fullpath, bt);

        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

private void SetText(string text)
{
    // InvokeRequired required compares the thread ID of the
    // calling thread to the thread ID of the creating thread.
    // If these threads are different, it returns true.
    if (lblFileName.InvokeRequired)
    {
        SetTextCallback d = new SetTextCallback(SetText);
        this.Invoke(d, new object[] { text });
    }
    else
    {
        this.lblFileName.Text = text;
    }
}
private void SetProgress(int i)
{
    if (progressBar1.InvokeRequired)
    {
        SetProgressCallback p = new SetProgressCallback(SetProgress);
        this.Invoke(p, new object[] { i });
    }
    else
    {
        this.progressBar1.Value = i;
    }
}
}
公共部分类表单1:表单
{
int MaxFileCounter=0;
静态int FileCounter=0;
委托无效SetTextCallback(字符串文本);
委托无效SetProgressCallback(int i);
私有无效按钮6_单击(对象发送者,事件参数e)
{
Task Task=Task.Factory.StartNew(()=>
{
编辑文件(txtFilePath.Text);
});
task.Wait();
MessageBox.Show(“完成”);
}
私有void编辑文件(字符串directoryPath)
{
尝试
{
//DirectoryInfo dirInfo=新的DirectoryInfo(txtFilePath.Text);
DirectoryInfo dirInfo=新的DirectoryInfo(directoryPath);
//字符串[]扩展数组={.jpg“,.png“,.gif“,.jpeg”};
string[]extensionArray=TxtensionList.Text.Split(“;”);
HashSet allowedExtensions=新的HashSet(extensionArray、StringComparer.OrdinalIgnoreCase);
FileInfo[]files=Array.FindAll(dirInfo.GetFiles(),f=>allowedExtensions.Contains(f.Extension));
可写文件(文件);
foreach(dirInfo.GetDirectories()中的DirectoryInfo目录)
{
编辑文件(目录全名);
}
}
捕获(例外情况除外)
{
MessageBox.Show(例如Message);
}
}
私有void writefile(FileInfo[]文件)
{
尝试
{
foreach(文件中的FileInfo FileInfo)
{
记忆流mo;
使用(Image=Image.FromFile(fileinfo.FullName))
{
SetText(fileinfo.FullName);
FileCounter++;
SetProgress(文件计数器*100/MaxFileCounter);
mo=(MemoryStream)优化图像(image,int.Parse(txtPercent.Text));
}
字节[]bt=新字节[mo.Length];
mo.Read(bt,0,bt.Length);
mo.Flush();
mo.Close();
字符串fullpath=fileinfo.FullName;
File.writealBytes(完整路径,bt);
}
}
捕获(例外情况除外)
{
MessageBox.Show(例如Message);
}
}
私有void SetText(字符串文本)
{
//invokererequired比较
//向创建线程的线程ID调用线程。
//如果这些线程不同,则返回true。
if(lblFileName.invokererequired)
{
SetTextCallback d=新的SetTextCallback(SetText);
调用(d,新对象[]{text});
}
其他的
{
this.lblFileName.Text=文本;
}
}
私有进程(int i)
{
如果(progressBar1.InvokeRequired)
{
SetProgressCallback p=新的SetProgressCallback(SetProgress);
调用(p,新对象[]{i});
}
其他的
{
this.progressBar1.Value=i;
}
}
}
我怎么办

    this.Invoke(d, new object[] { text });
使用任务的意义在于不要等待它。如果您仍然这样做,那么您将挂起UI线程。它会变得紧张,不再对来自Windows的通知做出响应。包括您自己的代码生成的代码,就像Invoke()调用一样。它向UI线程发送一条消息,以查找要调用的委托

因此Invoke()调用无法完成,UI线程挂起。Task.Wait()调用无法完成,因为任务挂起在Invoke()调用上。一个致命的拥抱,一个标准的线程错误称为死锁


请注意,BeginInvoke()没有这个问题,它不会等待完成。解决了死锁,不会为您提供实时更新,因为您仍然有一个死气沉沉的UI线程。必须删除Wait()调用。通过使用TaskScheduler.FromCurrentSynchronizationContext()添加任务延续,可以运行MessageBox.Show()调用。当用户关闭窗口时,您需要担心让任务停止,让它继续运行(通常)不会有好结果。添加到C#version 5中的async/await关键字是解决此问题的更通用的方法。

“我如何处理它?”-删除
任务。Wait()。它在错误的时刻做了错误的事情。我知道如果我删除它,它会起作用。那么当作业完成时,我应该何时通知用户?处理大量文件时?@Hamed_gibago启动任务并等待任务完成与在UI线程中运行代码(编辑文件)之间没有区别。在这两种情况下,UI都将是无响应的。让EditFiles知道其递归深度,并在顶层完成时引发事件。我应该如何做?我添加了一个条件,如果(FileCounter==MaxFileCounter)MessageBox.Show(“finished”);在File.writealBytes之后(完整路径,bt);在writeFiles方法中。检查作业是否完成以及是否跟踪了所有文件。并删除了按钮6中的task.wait()。它起作用了。但并没有解决穿线的问题。这是个好办法吗?我接受了你的回答,没关系。我将对此进行测试。但是谈谈我的解决方案。好还是坏?