多线程LOCK时的怪事

mathieuxiao 2007-12-03 05:08:14
希望用三个线程来递减标签上的数字,可是主窗体一直不出现,直到标签的值为0的时候才显示(此时子线程运行完毕),但是如果把线程减为2个,就正常运行,看到标签数字逐步减小。同样代码在03下运行也没有问题。不知道为什么会这样?
public partial class FrmMain : Form
{
Thread th1;
Thread th2;
Thread th3;

public FrmMain()
{
InitializeComponent();
Form.CheckForIllegalCrossThreadCalls = false;
}

private void FrmMain_Load(object sender, EventArgs e)
{
th1 = new Thread(ChangeNumber);
th2 = new Thread(ChangeNumber);
th3 = new Thread(ChangeNumber);

th1.Start();
th2.Start();
th3.Start();
}

public void ChangeNumber()
{
lock (this)
{
while (int.Parse(this.label1.Text) > 0)
{
Thread.Sleep(1000);
this.label1.Text = (int.Parse(this.label1.Text) - 1).ToString();
}
}
}

private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
{
th1.Abort();
th2.Abort();
th3.Abort();
}
}
...全文
184 7 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
boblaw 2007-12-04
  • 打赏
  • 举报
回复
你可以手動調用this.Show();
hooo 2007-12-04
  • 打赏
  • 举报
回复
//摘自msdn。。lz可以看一下

這類物件繫結到特定的執行緒,並且不是安全執行緒 (Thread-Safe)。如果您從不同的執行緒呼叫方法,則必須使用 方法來封送處理對適當執行緒的呼叫。這個屬性可以用來判斷是否一定要呼叫叫用 (Invoke) 方法,此一功能在您無法確知那一個執行緒擁有控制項時,就顯得十分好用。

注意事項
除了 InvokeRequired 屬性以外,控制項上還有四種安全執行緒 (Thread Safe) 的方法可以呼叫:Invoke、BeginInvoke、EndInvoke 和 CreateGraphics。至於其他所有的方法呼叫,則應使用其中一個叫用方法,將呼叫封送處理至控制項的執行緒。


如果控制項的控制代碼尚未存在,InvokeRequired 會往上搜尋控制項的父鏈結,直到找到具有視窗控制代碼的控制項或表單為止。如果找不到適當的控制代碼,InvokeRequired 方法會傳回 false。

這就表示,如果不需要 Invoke (發生在相同執行緒上的呼叫) 時,或是控制項建立在不同的執行緒上,但是尚未建立控制項的控制代碼時,InvokeRequired 可能會傳回 false。

如果尚未建立控制項的控制代碼,您不應該僅是呼叫控制項上的屬性、方法或事件。這樣做可能會在背景執行緒上建立控制項的控制代碼、在沒有訊息幫浦 (Message Pump) 下隔離執行緒上的控制項,並讓應用程式變得不穩定。

當 InvokeRequired 在背景執行緒上傳回 false 時,您也可以藉由檢查 IsHandleCreated 的值來防止這樣的情況發生。如果尚未建立控制項的控制代碼,您必須先等候它建立之後,再呼叫 Invoke 或 BeginInvoke。一般來說,這個情況只會發生在顯示表單或呼叫 Application.Run 之前,在應用程式的主要表單之建構函式內建立了背景執行緒時 (如同在 Application.Run(new MainForm()) 中)。

一個解決方案是等候表單的控制代碼建立之後,再啟動背景執行緒。您可以藉由呼叫 Handle 屬性來強制建立控制代碼,或是等候 Load 事件啟動背景處理序。

另外還有一個更好的解決方案,就是使用 SynchronizationContext 所傳回的 SynchronizationContext,而不是跨執行緒封送處理的控制項。

注意事項
如果應該處理訊息的執行緒已不在作用中,可能會擲回例外狀況。


如需有關多執行緒 Windows Form 控制項的詳細資訊,請參閱<HOW TO:使用背景執行緒搜尋檔案>(多執行緒 Windows Form 控制項範例)。
mathieuxiao 2007-12-04
  • 打赏
  • 举报
回复
楼上的,谢谢了。
我希望知道的为什么在加载事件里面开始子线程就出现子线程执行完毕之后,主窗体才显示的原因。麻烦你给我指点一下!
boblaw 2007-12-04
  • 打赏
  • 举报
回复

delegate void ChangeNumberCallBack();
public void ChangeNumber()
{
if (this.label1.InvokeRequired)
{
ChangeNumberCallBack cb = new ChangeNumberCallBack(ChangeNumber);
this.Invoke(cb);
}
else
{
lock(this)
{
while (int.Parse(this.label1.Text) > 0)
{
Thread.Sleep(1000);
this.label1.Text=(int.Parse(this.label1.Text) - 1).ToString();
}
}
}
}
fengyupeng 2007-12-03
  • 打赏
  • 举报
回复
delege
occam 2007-12-03
  • 打赏
  • 举报
回复
用安全方法访问label试试看,这里容易出问题的
mathieuxiao 2007-12-03
  • 打赏
  • 举报
回复
现在发现如果把加载事件里面的代码放在其它方法中,代码就ok。不知道为什么写在加载事件里面的代码在调用多线程时会出现这中情况,请高手指点一二

111,096

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧