我是线程的新手,我想知道如何使用它们在非确定性有限自动机中进行评估.
public bool Evaluate2(string s) { accepted = false; ThreadEval(s,StartState); return accepted; }
变量接受是一个类成员,我用它来控制其他线程何时应该停止.
void ThreadEval(string s,State q) { if (s.Length == 0 && q.IsFinal) { accepted = true; return; } bool found = true; State current = q; for (int i = 0; found && !accepted && i < s.Length; i++) { found = false; foreach (Transition t in current.transitions) if (t.symbol == s[i]) { Thread thread = new Thread(new ThreadStart(delegate { ThreadEval(s.Substring(i+1),t.to); })); thread.Start(); found = true; } } }
我的每个州都有一组过渡.转换由符号和消耗该符号的状态组成.因此,每当找到可能的转换时,我想创建一个新线程并检查字符串的其余部分(没有当前字符)…
我目前遇到两个问题:
>在ThreadEval内创建的所有线程完成之前,正在执行“return accepted”.有没有办法确保它不会返回,直到那些线程结束?
我在返回之前放了一个Thread.Sleep(200)并且它工作但是对于大字符串来说200 ms可能还不够,我也不想提高值,所以小字符串需要的时间比应该处理的要长.
>代码的方式是导致一些索引异常…我99.999%确定它是正确的,但它只会停止崩溃,如果我调用子串传递值i而不是i 1. ..但如果我只用i调用它将永远不会到达字符串的末尾,并且取决于自动机配置可能导致无限循环.我不确切地知道线程是如何工作的,但我怀疑可能有些并行处理在子串切片之前改变了i的值.
我怎么能保证每当我调用一个新线程时我只丢弃当前的char?
如果有人对如何使用更优雅的线程有任何建议,我将不胜感激,到目前为止,我发现在线程分配的函数中传递参数的唯一方法是使用委托.
解决方法
为了阻塞直到线程t执行完成,您可以使用Thread.Join.
t.Join();
这将主线程置于IDLE状态,直到线程t完成.
这意味着你必须跟踪在foreach循环中创建的所有线程,然后逐个连接它们.
更好的方法是使用TPL的任务< T>而不是直接使用线程.你的代码有点像这样:
Task ThreadEval(string s,State q) { //... List<Task> tasks = new List<Task>(); for (int i = 0; found && !accepted && i < s.Length; i++) { found = false; foreach (Transition t in current.transitions) if (t.symbol == s[i]) { tasks.Add( Task.Run( () => await ThreadEval(s.Substring(i+1),t.to))); found = true; } } return Task.WhenAll(tasks); } await ThreadEval(...);
>更改签名以返回Task而不是void
>创建所有正在运行的任务的列表
> Task.WhenAll将创建一个新任务,当任务列表中的所有任务都标记为完成时,该任务将被标记为完成.返回此任务.
然后调用者将等待ThreadEval.