Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.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# 多线程问题,可能是使用Foreach的死锁_C#_.net_Task Parallel Library_Parallel.foreach - Fatal编程技术网

C# 多线程问题,可能是使用Foreach的死锁

C# 多线程问题,可能是使用Foreach的死锁,c#,.net,task-parallel-library,parallel.foreach,C#,.net,Task Parallel Library,Parallel.foreach,Parallel.ForEach继续运行,我的程序不会结束。在第一次迭代之后,我无法跟踪它的去向。我的猜测是,它会陷入死锁,并继续进行上下文切换 private void ReadInputFile() { var collection = new ConcurrentBag<PropertyRecord>(); var lines = System.IO.File.ReadLines(InputFileName); int i = 0; int Re

Parallel.ForEach
继续运行,我的程序不会结束。在第一次迭代之后,我无法跟踪它的去向。我的猜测是,它会陷入死锁,并继续进行上下文切换

private void ReadInputFile()
{
    var collection = new ConcurrentBag<PropertyRecord>();
    var lines = System.IO.File.ReadLines(InputFileName);
    int i = 0;
    int RecordsCount = lines.Count();
    Parallel.ForEach(lines, line =>
    {
        if (string.IsNullOrWhiteSpace(line))
        {
            return;                    
        }

        var tokens = line.Split(',');
        var postalCode = tokens[0];
        var country = tokens.Length > 1 ? tokens[1] : "england";

        SetLabelNotifyTwoText(
            string.Format(
                "Reading PostCode {0} out of {1}"
                i,
                lines.Length));

        var tempRecord = GetAllAddesses(postalCode, country);
        if (tempRecord != null)
        {
            foreach (PropertyRecord r in tempRecord)
            {
                collection.Add(r);
            }
        }    
    });
}

private List<PropertyRecord> GetAllAddesses(
        string postalCode,
        string country = "england")
{
    SetLabelNotifyText("");
    progressBar1.Value = 0;
    progressBar1.Update();

    var records = new List<PropertyRecord>();
    using (WebClient w = new WebClient())
    {
        var url = CreateUrl(postalCode, country);
        var document = w.DownloadString(url);
        var pagesCount = GetPagesCount(document);
        if (pagesCount == null)
        {
            return null;
        }

        for (int i = 0; i < pagesCount; i++)
        {
            SetLabelNotifyText(
                string.Format(
                    "Reading Page {0} out of {1}",
                    i,
                    pagesCount - 1));

            url = CreateUrl(postalcode,country, i);
            document = w.DownloadString(url);
            var collection = Regex.Matches(
                document,
                "<div class=\"soldDetails\">(.|\\n|\\r)*?class=" +
                "\"soldAddress\".*?>(?<address>.*?)(</a>|</div>)" +
                "(.|\\n|\\r)*?class=\\\"noBed\\\">(?<noBed>.*?)" +
                "</td>|</tbody>");

            foreach (var match in collection)
            {
                var r = new PropertyRecord();

                var bedroomCount = match.Groups["noBed"].Value;
                if(!string.IsNullOrEmpty(bedroomCount))
                {
                    r.BedroomCount = bedroomCount;             
                }
                else
                {
                    r.BedroomCount = "-1";
                }

                r.address = match.Groups["address"].Value;

                var line = string.Format(
                    "\"{0}\",{1}",
                    r.address
                    r.BedroomCount);
                OutputLines.Add(line);

                Records.Add(r);
            }
        }
    }

    return Records;
}
private void ReadInputFile()
{
var集合=新的ConcurrentBag();
var lines=System.IO.File.ReadLines(InputFileName);
int i=0;
int recordscont=lines.Count();
Parallel.ForEach(行,行=>
{
if(string.IsNullOrWhiteSpace(行))
{
返回;
}
var tokens=line.Split(',');
var postalCode=令牌[0];
var country=tokens.Length>1?tokens[1]:“英格兰”;
SetLabelNotifyTwoText(
字符串格式(
“正在从{1}中读取邮政编码{0}”
我
行(长度);
var tempRecord=GetAllAddEss(后代码,国家/地区);
if(tempRecord!=null)
{
foreach(临时记录中的PropertyRecord r)
{
集合。添加(r);
}
}    
});
}
私人名单(
字符串后代码,
string country=“英格兰”)
{
SetLabelNotifyText(“”);
progressBar1.值=0;
progressBar1.Update();
var记录=新列表();
使用(WebClient w=新WebClient())
{
var url=CreateUrl(postalCode,国家/地区);
var document=w.DownloadString(url);
var PageScont=GetPageScont(文档);
如果(PageScont==null)
{
返回null;
}
for(int i=0;i(?*?)(|)+
“(.|\\n |\\r)*?class=\\\\“noBed\\\”>(?*?)+
"|");
foreach(集合中的变量匹配)
{
var r=新属性记录();
var beddroomcount=match.Groups[“noBed”].Value;
如果(!string.IsNullOrEmpty(beddroomCount))
{
r、 卧室数量=卧室数量;
}
其他的
{
r、 卧室数=“-1”;
}
r、 地址=匹配。组[“地址”]。值;
var line=string.Format(
"\"{0}\",{1}",
r、 地址
r、 卧室数量);
输出行。添加(行);
记录。添加(r);
}
}
}
退货记录;
}
它在没有
Parallel.ForEach
的情况下运行良好,但使用
Parallel.ForEach
符合要求


我已经调试了它,第一次从
getAllAddresses
-方法返回后,Step Next按钮停止,它只是在后台继续调试。它不会出现在我放置的任何书签上。

正如您在评论中所说,您的
SetLabelNotifyText
SetLabelNotifyTwoText
方法调用
控件。调用

对于
Control.Invoke
要工作,主线程必须是空闲的,但是在您的情况下,您似乎通过调用其中的
Parallel.ForEach
来阻止主线程

这是一个最小的复制:

private void button1_Click(object sender, EventArgs e)
{
    Parallel.ForEach(Enumerable.Range(1, 100), (i) =>
    {
        Thread.Sleep(10);//Simulate some work
        this.Invoke(new Action(() => SetText(i)));
    });
}

private void SetText(int i)
{
    textBox1.Text = i.ToString();
}
主线程等待
并行。ForEach
和工作线程等待主线程,从而导致死锁

如何修复:不要使用
Invoke
只需使用
BeginInvoke
或不要阻塞主线程


如果这不是案例帖子,那将对我们有所帮助

正如您在评论中所说,您的
SetLabelNotifyText
SetLabelNotifyTwoText
方法调用
Control.Invoke

对于
Control.Invoke
要工作,主线程必须是空闲的,但是在您的情况下,您似乎通过调用其中的
Parallel.ForEach
来阻止主线程

这是一个最小的复制:

private void button1_Click(object sender, EventArgs e)
{
    Parallel.ForEach(Enumerable.Range(1, 100), (i) =>
    {
        Thread.Sleep(10);//Simulate some work
        this.Invoke(new Action(() => SetText(i)));
    });
}

private void SetText(int i)
{
    textBox1.Text = i.ToString();
}
主线程等待
并行。ForEach
和工作线程等待主线程,从而导致死锁

如何修复:不要使用
Invoke
只需使用
BeginInvoke
或不要阻塞主线程


如果这不是案例帖子,这将有助于我们

像这样更改代码,以便使用。这是使用
BeginInvoke
和其他异步代码模型的现代替代方案

private async Task ReadInputFile()
{
    var collection = new ConcurrentBag<PropertyRecord>();
    var lines = System.IO.File.ReadLines(InputFileName);
    int i = 0;
    int RecordsCount = lines.Count();
    Parallel.ForEach(lines, line =>
    {
        if (string.IsNullOrWhiteSpace(line))
        {
            return;                    
        }

        var tokens = line.Split(',');
        var postalCode = tokens[0];
        var country = tokens.Length > 1 ? tokens[1] : "england";

        SetLabelNotifyTwoText(
            string.Format(
                "Reading PostCode {0} out of {1}"
                i,
                lines.Length));

        var tempRecord = await GetAllAddesses(postalCode, country);
        if (tempRecord != null)
        {
            foreach (PropertyRecord r in tempRecord)
            {
                collection.Add(r);
            }
        }    
    });
}

private async Task<List<PropertyRecord>> GetAllAddesses(
        string postalCode,
        string country = "england")
{
    SetLabelNotifyText("");
    progressBar1.Value = 0;
    progressBar1.Update();

    var records = new List<PropertyRecord>();
    using (WebClient w = new WebClient())
    {
        var url = CreateUrl(postalCode, country);
        var document = await w.DownloadStringTaskAsync(url);
        var pagesCount = GetPagesCount(document);
        if (pagesCount == null)
        {
            return null;
        }

        for (int i = 0; i < pagesCount; i++)
        {
            SetLabelNotifyText(
                string.Format(
                    "Reading Page {0} out of {1}",
                    i,
                    pagesCount - 1));

            url = CreateUrl(postalcode,country, i);
            document = await w.DownloadStringTaskAsync(url);
            var collection = Regex.Matches(
                document,
                "<div class=\"soldDetails\">(.|\\n|\\r)*?class=" +
                "\"soldAddress\".*?>(?<address>.*?)(</a>|</div>)" +
                "(.|\\n|\\r)*?class=\\\"noBed\\\">(?<noBed>.*?)" +
                "</td>|</tbody>");

            foreach (var match in collection)
            {
                var r = new PropertyRecord();

                var bedroomCount = match.Groups["noBed"].Value;
                if(!string.IsNullOrEmpty(bedroomCount))
                {
                    r.BedroomCount = bedroomCount;             
                }
                else
                {
                    r.BedroomCount = "-1";
                }

                r.address = match.Groups["address"].Value;

                var line = string.Format(
                    "\"{0}\",{1}",
                    r.address
                    r.BedroomCount);
                OutputLines.Add(line);

                Records.Add(r);
            }
        }
    }

    return Records;
}
或者,更好的是,调用方是
异步的

await ReadInputFile();

像这样更改代码,以便使用。这是使用
BeginInvoke
和其他异步代码模型的现代替代方案

private async Task ReadInputFile()
{
    var collection = new ConcurrentBag<PropertyRecord>();
    var lines = System.IO.File.ReadLines(InputFileName);
    int i = 0;
    int RecordsCount = lines.Count();
    Parallel.ForEach(lines, line =>
    {
        if (string.IsNullOrWhiteSpace(line))
        {
            return;                    
        }

        var tokens = line.Split(',');
        var postalCode = tokens[0];
        var country = tokens.Length > 1 ? tokens[1] : "england";

        SetLabelNotifyTwoText(
            string.Format(
                "Reading PostCode {0} out of {1}"
                i,
                lines.Length));

        var tempRecord = await GetAllAddesses(postalCode, country);
        if (tempRecord != null)
        {
            foreach (PropertyRecord r in tempRecord)
            {
                collection.Add(r);
            }
        }    
    });
}

private async Task<List<PropertyRecord>> GetAllAddesses(
        string postalCode,
        string country = "england")
{
    SetLabelNotifyText("");
    progressBar1.Value = 0;
    progressBar1.Update();

    var records = new List<PropertyRecord>();
    using (WebClient w = new WebClient())
    {
        var url = CreateUrl(postalCode, country);
        var document = await w.DownloadStringTaskAsync(url);
        var pagesCount = GetPagesCount(document);
        if (pagesCount == null)
        {
            return null;
        }

        for (int i = 0; i < pagesCount; i++)
        {
            SetLabelNotifyText(
                string.Format(
                    "Reading Page {0} out of {1}",
                    i,
                    pagesCount - 1));

            url = CreateUrl(postalcode,country, i);
            document = await w.DownloadStringTaskAsync(url);
            var collection = Regex.Matches(
                document,
                "<div class=\"soldDetails\">(.|\\n|\\r)*?class=" +
                "\"soldAddress\".*?>(?<address>.*?)(</a>|</div>)" +
                "(.|\\n|\\r)*?class=\\\"noBed\\\">(?<noBed>.*?)" +
                "</td>|</tbody>");

            foreach (var match in collection)
            {
                var r = new PropertyRecord();

                var bedroomCount = match.Groups["noBed"].Value;
                if(!string.IsNullOrEmpty(bedroomCount))
                {
                    r.BedroomCount = bedroomCount;             
                }
                else
                {
                    r.BedroomCount = "-1";
                }

                r.address = match.Groups["address"].Value;

                var line = string.Format(
                    "\"{0}\",{1}",
                    r.address
                    r.BedroomCount);
                OutputLines.Add(line);

                Records.Add(r);
            }
        }
    }

    return Records;
}
或者,更好的是,调用方是
异步的

await ReadInputFile();

从这里调试会更加困难。我已经调试过了,第一次从GetAllAddresss(..)返回时,我不知道在哪里使用调试器。
SetLabelNotifyText
SetLabelNotifyTwoText
还有什么作用?这会调用
控件。调用
?哪个线程调用的是主线程?是的,它们是用来阻止illegel线程访问问题以进行更新的GUI@Charlie很高兴能提供帮助,但这里绝对没有远程调试会话!请自己做作业,调查正在运行的任务/线程/堆栈!这是非常不可能有一个答案,准确地指出了非常困扰你的那一行,因为这个问题没有遵循。这将是更难调试从这里。我已经调试了它,第一次从GetAllAddresss(…)返回它去,我不知道在哪里使用调试器请。还有什么是
SetLabelNotifyText
SetLabelNotif