这位兄台,好象你的代码很复杂。我前几天写了一下,表述力不佳,仅贴代码。 public class ThreadRunCode { public Thread th; public bool bExceptRun=true;//是否结束线程,这个可以在外控制线程 public bool bSleep=true;//本次线程的时间片是否执行事件。 private System.Windows.Forms.Form frm; public delegate void ThreadRunMthod(); public event ThreadRunMthod threadRunMthod; public void RunThread() { th = new Thread(new ThreadStart(RunThreadCode)); th.Start(); } private void RunThreadCode() { do { if (bSleep) { continue; } this.frm.Invoke(threadRunMthod); } while (bExceptRun); } }在Form中调用举例: public int i; //others code ThreadRunCode threadRunCode=new ThreadRunCode(this); threadRunCode.threadRunMthod += new ThreadRunMthod(ThreadRunCode_threadRunMthod); threadRunCode.bSleep=false; threadRunCode.RunThread(); //others code void ThreadRunCode_threadRunMthod() { textBox1.text=(i++).ToString(); } 这样写是不是也可以实现多线程,其实我在想,多线程同一时刻尽量少,应该他存在的时候才启动。比如你说的例子,我认为在要修改界面的时候再建一个线珵,修改完后就终止线程,再改变的时候再建一个。
远离反射,通常更能够保证性能。而且以下方法更加直观和方便。在你的工程中的扩展方法类中写下一个SafeCall方法:using System; using System.Windows.Forms;namespace WindowsFormsApplication1 { public static class Extensions { public static void SafeCall(this Control ctrl, Action callback) { if (ctrl.InvokeRequired) ctrl.Invoke(callback); else callback(); } } } 它只是把你要保护起来的代码作为一个回调而已。然后任何需要保护一些代码的地方都可以这样调用:using System; using System.Threading; using System.Windows.Forms;namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { ThreadPool.QueueUserWorkItem(h => { for (var i = 0; i < 10000000; i++) { label1.SafeCall(() => { label1.Text = i.ToString(); }); Thread.Sleep(100); } }); } } }
当然,使用lamda是我的一个“坏毛病”。其实这里完全可以使用传统的匿名委托写法:using System; using System.Threading; using System.Windows.Forms;namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { ThreadPool.QueueUserWorkItem(h => { for (var i = 0; i < 10000000; i++) { label1.SafeCall(delegate() { label1.Text = i.ToString(); }); Thread.Sleep(100); } }); } } }
注明一下:此文内容基于.NET 2.0 新的.NET有很方便的实现跨线程访问的能力,参见楼上
不错,作为分享,应该使用较新的技术。 C#的出路不在于跟java比谁更老。
public delegate void DoWorkD(int N); public DoWorkD d; public void DoWork(int Nums) { if (textBox1.InvokeRequired) { textBox1.Invoke(d, Nums); } else textBox1.Text += Nums.ToString() + "-"; } public void ThreadDoWork() { Thread.Sleep(new Random().Next(100, 1000)); int i=0; while (true) { d = new DoWorkD(DoWork); Thread.Sleep(new Random().Next(100, 1000)); DoWork(i); i++; } } private void button1_Click(object sender, EventArgs e) { for (int i = 0; i < 20; i++) { Thread a = new Thread(ThreadDoWork); a.IsBackground = true; a.Start(); } }这样就可以了.net 2.0例子在这http://download.csdn.net/detail/wawd74520/4479927
支持一个,我也是用.net 2.0的。现在有这个InvokeHelper,应该会方便很多了。 野比,加一个:BeginInvoke 下去会更完美一点。以前破旧的代码: Private Delegate Sub ShowMsgCallBack(ByVal msg As String) Private Delegate Sub SetBtnTextCallBack(ByVal text As String) Private Sub ShowPanel() If Me.PnlDownInfo.InvokeRequired Then Dim mi As New MethodInvoker(AddressOf ShowPanel) Me.BeginInvoke(mi) Else Me.PnlDownInfo.Visible = Not Me.PnlDownInfo.Visible End If End Sub Private Sub ShowMsg(ByVal msg As String) If Me.LBDownloadInfo.InvokeRequired Then Dim cb As New ShowMsgCallBack(AddressOf ShowMsg) '如使用Invoke会等到函数调用结束,而BeginInvoke不会等待直接往后走 Me.BeginInvoke(cb, New Object() {msg}) Else Me.LBDownloadInfo.Text = msg Me.LBDownloadInfo.Refresh() End If End Sub Private Sub PerFinishDownLoad(ByVal fname As String) If Me.LvFiles.InvokeRequired Then Dim cb As New ShowMsgCallBack(AddressOf PerFinishDownLoad) Me.BeginInvoke(cb, New Object() {fname}) Else Dim item As ListViewItem item = Me.LvFiles.FindItemWithText(fname) If item IsNot Nothing Then item.SubItems(2).Text = "完成" End If End If End Sub
Private Sub ResetDownLoadPrg() If Me.InvokeRequired Then Dim mi As New MethodInvoker(AddressOf ResetDownLoadPrg) Me.BeginInvoke(mi) Else Me.SmoothProgressBar1.Value = 0 Me.LBDownloadInfo.Text = "下载信息" End If End Sub
Private Sub ResetDownLoadBtn() If Me.BtnRunUpdate.InvokeRequired Or Me.BtnCancel.InvokeRequired Then Dim mi As New MethodInvoker(AddressOf ResetDownLoadBtn) Me.BeginInvoke(mi) Else Me.BtnRunUpdate.Enabled = True Me.BtnRunUpdate.Text = "完成(&F)" Me.BtnCancel.Enabled = False End If End Sub
{
public Thread th;
public bool bExceptRun=true;//是否结束线程,这个可以在外控制线程
public bool bSleep=true;//本次线程的时间片是否执行事件。
private System.Windows.Forms.Form frm; public delegate void ThreadRunMthod();
public event ThreadRunMthod threadRunMthod; public void RunThread()
{
th = new Thread(new ThreadStart(RunThreadCode));
th.Start();
}
private void RunThreadCode()
{
do
{
if (bSleep)
{
continue;
}
this.frm.Invoke(threadRunMthod);
} while (bExceptRun);
}
}在Form中调用举例: public int i;
//others code
ThreadRunCode threadRunCode=new ThreadRunCode(this);
threadRunCode.threadRunMthod += new ThreadRunMthod(ThreadRunCode_threadRunMthod);
threadRunCode.bSleep=false;
threadRunCode.RunThread();
//others code
void ThreadRunCode_threadRunMthod()
{
textBox1.text=(i++).ToString();
} 这样写是不是也可以实现多线程,其实我在想,多线程同一时刻尽量少,应该他存在的时候才启动。比如你说的例子,我认为在要修改界面的时候再建一个线珵,修改完后就终止线程,再改变的时候再建一个。
using System.Windows.Forms;namespace WindowsFormsApplication1
{
public static class Extensions
{
public static void SafeCall(this Control ctrl, Action callback)
{
if (ctrl.InvokeRequired)
ctrl.Invoke(callback);
else
callback();
}
}
}
它只是把你要保护起来的代码作为一个回调而已。然后任何需要保护一些代码的地方都可以这样调用:using System;
using System.Threading;
using System.Windows.Forms;namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void Form1_Load(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(h =>
{
for (var i = 0; i < 10000000; i++)
{
label1.SafeCall(() =>
{
label1.Text = i.ToString();
});
Thread.Sleep(100);
}
});
} }
}
using System.Threading;
using System.Windows.Forms;namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void Form1_Load(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(h =>
{
for (var i = 0; i < 10000000; i++)
{
label1.SafeCall(delegate()
{
label1.Text = i.ToString();
});
Thread.Sleep(100);
}
});
} }
}
新的.NET有很方便的实现跨线程访问的能力,参见楼上
C#的出路不在于跟java比谁更老。
public delegate void DoWorkD(int N); public DoWorkD d; public void DoWork(int Nums)
{
if (textBox1.InvokeRequired)
{
textBox1.Invoke(d, Nums);
}
else
textBox1.Text += Nums.ToString() + "-";
} public void ThreadDoWork()
{
Thread.Sleep(new Random().Next(100, 1000));
int i=0;
while (true)
{
d = new DoWorkD(DoWork);
Thread.Sleep(new Random().Next(100, 1000));
DoWork(i);
i++;
}
} private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 20; i++)
{
Thread a = new Thread(ThreadDoWork);
a.IsBackground = true;
a.Start();
}
}这样就可以了.net 2.0例子在这http://download.csdn.net/detail/wawd74520/4479927
野比,加一个:BeginInvoke 下去会更完美一点。以前破旧的代码: Private Delegate Sub ShowMsgCallBack(ByVal msg As String)
Private Delegate Sub SetBtnTextCallBack(ByVal text As String) Private Sub ShowPanel()
If Me.PnlDownInfo.InvokeRequired Then
Dim mi As New MethodInvoker(AddressOf ShowPanel)
Me.BeginInvoke(mi)
Else
Me.PnlDownInfo.Visible = Not Me.PnlDownInfo.Visible
End If
End Sub Private Sub ShowMsg(ByVal msg As String)
If Me.LBDownloadInfo.InvokeRequired Then
Dim cb As New ShowMsgCallBack(AddressOf ShowMsg)
'如使用Invoke会等到函数调用结束,而BeginInvoke不会等待直接往后走
Me.BeginInvoke(cb, New Object() {msg})
Else
Me.LBDownloadInfo.Text = msg
Me.LBDownloadInfo.Refresh()
End If
End Sub Private Sub PerFinishDownLoad(ByVal fname As String)
If Me.LvFiles.InvokeRequired Then
Dim cb As New ShowMsgCallBack(AddressOf PerFinishDownLoad)
Me.BeginInvoke(cb, New Object() {fname})
Else
Dim item As ListViewItem
item = Me.LvFiles.FindItemWithText(fname)
If item IsNot Nothing Then
item.SubItems(2).Text = "完成"
End If
End If
End Sub
Private Sub ResetDownLoadPrg()
If Me.InvokeRequired Then
Dim mi As New MethodInvoker(AddressOf ResetDownLoadPrg)
Me.BeginInvoke(mi)
Else
Me.SmoothProgressBar1.Value = 0
Me.LBDownloadInfo.Text = "下载信息"
End If
End Sub
Private Sub ResetDownLoadBtn()
If Me.BtnRunUpdate.InvokeRequired Or Me.BtnCancel.InvokeRequired Then
Dim mi As New MethodInvoker(AddressOf ResetDownLoadBtn)
Me.BeginInvoke(mi)
Else
Me.BtnRunUpdate.Enabled = True
Me.BtnRunUpdate.Text = "完成(&F)"
Me.BtnCancel.Enabled = False
End If
End Sub
{})));子线程中需要访问 控件的话,我现在习惯了这样,很少判断这InvokeRequired个属性了
public delegate void ThreadInvokeDelegate(string type,params object[] args);
#region 静态方法,供其他线程调用,用于访问Form
public static event ThreadInvokeDelegate OnThreadInvoke;
public static ThreadInvoke(string type,params object[] args)
{
if(OnThreadInvoke!=null)
OnThreadInvoke(type,args);
}
#endregion在真正的form中(比如Form1),构造函数里注册这个静态事件
Form1.OnThreadInvoke+=new ThreadInvokeDelegate(Form1_OnThreadInvoke);这样就把任意线程调用Form1.ThreadInvoke方法转到了Form1_OnThreadInvoke中处理
这里的string type作为标识,来区分Form1需要进行的不同的操作,比如刷新列表,还是写日志,还是其他什么操作以上想法本人技术有限,不能很好的实现,希望有大哥能完善,并分享一下
夸线程访问控件,这一句代码不是就完了么。。
http://topic.csdn.net/u/20120810/14/17b442ae-5f57-4781-80a2-75aebb5568c6.html?seed=275715377&r=79381756#r_79381756
实际是否要委托本身就看需求,多线程是为了提高效率而存在的,不是为了降低效率,到处用委托违背了多线程的存在意义。
而实际对于简单的输出显示,应该直接对其操作,不要回调,设置CheckForIllegalCrossThreadCalls为false即可,有时候不检查能大大提高效率,而即使检测也不代表就一定能正常,因为多线程操作共享资源一般需要加锁,这和是否回调操作无关。