您的位置:首页 > 产品设计 > UI/UE

C# 多线程访问UI

2008-12-19 23:25 260 查看
Code

自己在做一个多线程的TCP端口扫描程序,由于要用到多线程技术,而C#对线程技术 的封装非常方便使用,且如果不做网络底层处理,C#使用套接字也非常方便,于是决定用C#.NET实现。 前面一切都很顺利,到后来要启用多线程技术,启用多个线程同时发送和接受数据,并且在收到返回信息时,根据情况对主窗体中的进度条和相关UI进行改变。在这个问题上总是出现问题:每当开始工作后,程序主窗体处于死亡状态,对用户操作没有任何反应。程序中对于扫描我是这样实现的:(部分伪代码)

public partial class Form1 : Form

{

private delegate void Method(); //委托申明,子线程条用UI中的方法

private ArrayList Config = new ArrayList();//模拟装所有端口配置

private ArrayList done = new ArrayList();//装完成端口

private long AlivedThread = 0;//当前存活线程数

public Form1()

{

InitializeComponent();

}

private void button1_Click(object sender, EventArgs e)

{

done.Clear();//将完成项清空

toolStripProgressBar1.Value = 0;//设置初始值

Random rand = new Random(200); //下面和循环,模拟初始化端口配置项

int max=rand.Next(1000);

for (int i = 0; i < max; i++)

{

Config.Add(rand.Next());

}

toolStripProgressBar1.Minimum = 0;

toolStripProgressBar1.Maximum = Config.Count;

foreach (object item in Config)//循环扫描每项

{

again: if (Interlocked.Read(ref AlivedThread) < 10)

{

Thread ScanThread= new Thread

(new ParameterizedThreadStart(ScanFunc));

ScanThread.Start(item);

Thread.Sleep(10);

}

else

{

Thread.Sleep(10);

goto again;

}

}

}

private void ScanFunc(object item)

{

Interlocked.Increment(ref AlivedThread);

Monitor.Enter(done);

done.Add(item);

Monitor.Exit(done);

Thread.Sleep(500);

SetProgressMethod();

Interlocked.Decrement(ref AlivedThread);

}

private void SetProgressMethod()

{

MethodInvoker mi = new MethodInvoker(this.SetProgressBar);

this.BeginInvoke(mi);

Thread.Sleep(100);

}

private void SetProgressBar()

{

Monitor.Enter(done);

toolStripProgressBar1.Value = done.Count;

Monitor.Exit(done);

this.Refresh();

}

就上面代码老是出现主窗体死亡,对用户操作没有任何反应的情况。我在网上四处找,一好心网友也给了我相关代码,但和我的类似,实例只有两个线程,一个线程主线程,一个控制进度条。今天看了CSDN上愈翁的一篇文章,内容同样很简单,也好似两个线程,和我得到的代码类似。但是我看到文章下面有网友提问,作者有一句关键的回答,“线程提交给UI处理A任务,而UI正在处理B任务”,我这才回过神来。原来我的主线程中有个foreach循环,UI线程一直处理它呢,没有时间相应子线程提交任务!

于是马上对代码做了修改:新建一线程函数,将循环放到该线程中执行,修改如下:

private void LoopFun()

{

foreach (object item in Config)//循环扫描每项

{

again: if (Interlocked.Read(ref AlivedThread) < 10)

{

Thread ScanThread= new Thread

(new ParameterizedThreadStart(ScanFunc));

ScanThread.Start(item);

Thread.Sleep(10);

}

else

{

Thread.Sleep(10);

goto again;

}

}

}

然后在主线程中申明另一线程执行该函数,

Thread loop = new Thread(new ThreadStart(LoopFun));

loop.Start();

测试,程序工作时,UI完全能正常反应用户操作了!

最后,在做多线程程序时,一定要遵循费时操作不放在主线程中的原则!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: