我有一个使用两个客户端线程和一个服务器的程序。我的程序中有一点我希望一个线程中的值能够影响另一个线程的路径。
更具体地说,我在服务器中有这个代码:
class Handler
{
public void clientInteraction(Socket connection, bool isFirstThread, Barrier barrier)
{
string pAnswer = string.Empty;
string endGameTrigger = string.Empty;
//setup streamReaders and streamWriters
while(true) //infinite game loop
{
//read in a question and send to both threads.
pAnswer = sr.ReadLine();
Console.WriteLine(pAnswer);
awardPoints();
writeToConsole("Press ENTER to ask another question or enter 0 to end the game", isFirstThread);
if(isFirstThread == true)
{
endGameTrigger = Console.ReadLine(); //this is only assigning to one thread...
}
barrier.SignalAndWait();
if(endGameTrigger == "0")//...meaning this is never satisfied in one thread
{
endGame();
}
}
}
}
布尔值isFirstThread
是在线程的构造函数中设置的值,我可以检测到哪个线程首先连接到该线程。
是否有某种方式,或者可能是线程方法,允许第二个连接的线程检测到第一个线程中的endGameTrigger
已被设置,因此两个线程都正确执行endGame()
方法。
答案 0 :(得分:1)
最关注多线程
但要谨慎行事。多个线程的错误使用/处理可能导致代码行为不可预测且不一致。大部分时间都会有效,然后没有明显的理由不起作用。错误很难重现和识别。
话虽这么说,处理多线程的一个基本概念是确保两个线程不会同时尝试更新相同的值。它们可以以单个线程无法实现的方式来破坏或部分修改值。
实现此目标的一种方法是使用locking。
private object _lockObject = new Object();
private string _myString;
void SetStringValue(string newValue)
{
lock(_lockObject)
{
_myString = newValue;
}
}
您通常拥有一个仅作为锁存在的对象。当一个线程进入lock
块时,它会获取对象的锁定。如果另一个线程已经锁定该对象,则下一个线程只是等待前一个线程释放锁。这确保了两个线程不能同时更新该值。
您希望尽可能减少lock
内的代码量,以便尽快释放锁定。并且要注意,如果它因多个锁而变得复杂,那么两个线程可以永久地相互阻塞。
对于递增和更新数字,还有interlocked operations处理锁定,确保这些操作一次由一个线程执行。
为了好玩,我写了这个控制台应用程序。它需要一个句子,将其分解为单词,然后使用多个线程将每个单词添加回新的字符串并输出该字符串。
using System;
using System.Threading.Tasks;
namespace FunWithThreading
{
class Program
{
static void Main(string[] args)
{
var sentence =
"I am going to add each of these words to a string "
+ "using multiple threads just to see what happens.";
var words = sentence.Split(' ');
var output = "";
Parallel.ForEach(words, word => output = output + " " + word);
Console.WriteLine(output);
Console.ReadLine();
}
}
}
前两次我运行它,输出字符串正是我开始使用的。太棒了,它完美无缺!然后我明白了:
I am going to add of these words to a string using multiple threads just to see what happens. each
然后我又跑了20次,无法重复这个错误。想象一下,如果这是一个真正的应用程序,并且像这样的事情发生了不可预测的事情,即使我一遍又一遍地测试,然后我无法再次发生这种情况。
所以关键在于多线程是邪恶的,但只是为了理解风险,只在需要时引入它,然后仔细考虑如何防止线程相互干扰。
答案 1 :(得分:0)
回应Luaan的评论。我已将endGameTrigger
作为private static string endGameTrigger
放在Handler类中。使其成为static
字段而不是本地方法变量允许handler
类(每个线程)的所有实例访问此变量的最新分配。非常感谢。