1.背景:有30台TCP设备需要同时建立套接字,并且需要一键对它们进行各种操作(传统单线程方法会导致界面长时间卡住,不能点击,且不会有实时信息返回)。
2.如何创建一个新的线程,与使用委托的方法直接传参与调用函数:
Thread thr = new Thread(())//创建单个线程
thr.Start();//启动
Thread n = new Thread(new ThreadStart(() => MyCode(a)));//使用委托并传递参数的写法
Thread n = new Thread(() => MyCode(a));//此为上行代码的简写
3.建立多个插座就是在全局先声明,等传入IP端口等数据后再赋值给它们,下面简单写个例子:
Socket sc1;
Socket sc2;
private void Button连接_Click(object sender, RoutedEventArgs e)
{
string sum = TBIP1.Text.Trim() + "," + TBIP2.Text.Trim();
string[] arr = sum.Split(',');
String IP1 = arr[0];
String IP2 = arr[1];
Thread thr1 = new Thread(() => Con(1, IP1));
Thread thr2 = new Thread(() => Con(2, IP2));
thr1.Start(); thr2.Start();
}
private void Con(int ID, string IP)
{
if (IP != "")
{
try
{
switch (ID)
{
case 1:
sc1 = ScanCtrl.Connect(IP, 4001, 1000);
bool flag1 = sc1.Connected;//根据设备返回值判断是否连接成功
if (flag1)
{
Conputsuc(ID);
}
else
{
Conputfalse(ID);
}
break;
//剩余部分省略了
}}}}
设备是否连接成功肯定是要提供反馈的,如果在上面代码的ConPutSuc(ID);处写对界面的操作的话会跨线程,如AppendText通过,会不允许操作,因为规定界面的操作必须在主线程完成,解决方案在第4条。
4.把操作转回到主线程,也就是我的ConPutSuc(ID);方法,使用Dispatcher.Invoke(new Action(()=> {//你的代码})):
private void Conputsuc(int ID)
{
Dispatcher.Invoke(new Action(() =>
{
TB信息.AppendText(ID + "号设备,连接成功!" + DateTime.Now + "\r\n");
TB信息.ScrollToEnd();
}));
}
如果是winform应用,是没有Dispatchar.Invoke的,可以使用BeginInvoke。
5.如果两个线程都操作了我的精读函数,肯定会导致输出顺序是随机的,或者有可能直接导致内部数据错乱,有很多种方法,这里就先忽略性能和线程独立,使用一种简单的方法来处理,就是给多线程操作的这一块内存或者说方法加锁,方法如下:
private object MyLock = new object();//先在外部创建一个锁对象
private void Con(int ID, string IP)
{
lock (MyLock)
{
//需要锁住的代码
}
}
这样锁住之后这块代码一次只能被一个线程操作,其它的先排队。