Thread 初学(二)——线程同步
在讨论thread的常用方法之前,有必要先说一说IsBackground属性。废话少说上代码。
1 private void Form1_Load(object sender, EventArgs e) 2 { 3 Thread t = new Thread(run); 4 t.Start(); 5 t.IsBackground=true; // 设置是否为后台线程 6 } 7 public void run() 8 { 9 while (true) 10 { 11 Thread.Sleep(1000); 12 } 13 }
加注释代码是设置IsBackground属性,如果设置为true,当主线程结束的时候,此线程必然结束。如果设置成false或者是不设置(就是注释掉第五行代码),就为前台线程,当主线程结束时,他也不结束。任然运行着。
下面记录线程同步学习笔记
线程同步可以使用以下三个类进行管理Interlocked(互锁类)Monitor(管理类)
Mutex(互斥体),还有一个简单的方法就是Lock();
Interlocked中常用的方法:
根据方法介绍,很明显如果我们的程序中需要做到线程同步,就需要一个自定义的“计数器”
以下是代码作为一个简单的线程同步例子:
界面效果图
代码:
private static long numberOfusedSpace = 0;//计数器也是个控制量用于互锁 int lenth = 0; private void button1_Click(object sender, EventArgs e) { if (button1.Text.Contains("开始")) { richTextBox1.ReadOnly = true; textBox1.ReadOnly = true; richTextBox2.ReadOnly = true; lenth = richTextBox1.Text.Trim().Length; Thread threadReadPoolA = new Thread(ReadPoolA); Thread threadWritePoolB = new Thread(WritePoolB); threadReadPoolA.IsBackground = true; threadWritePoolB.IsBackground = true; threadReadPoolA.Start(); threadWritePoolB.Start(); button1.Text = "清空 重来"; } else { richTextBox1.ReadOnly = false; textBox1.ReadOnly = true; richTextBox2.ReadOnly = false; foreach (Control temp in this.Controls) { if (temp.GetType().ToString().Contains("TextBox")) { temp.Text = ""; } } button1.Text = "开始流动; } } /// <summary> ///读取池子中的数据,并将它写入到管道(计数器)中 /// </summary> private void ReadPoolA() { UserControl.CheckForIllegalCrossThreadCalls = false; string s = richTextBox1.Text.Trim(); while (richTextBox1.Text.Trim().Length > 0) { while (Interlocked.Read(ref numberOfusedSpace) == 1) { Thread.Sleep(300); } textBox1.Text = s[0].ToString(); Interlocked.Increment(ref numberOfusedSpace); s = s.Substring(1); richTextBox1.Text = s; //Thread.Sleep(1000); } } /// <summary> /// 读取管道(计数器)中的数据,并将它写入到池子中 /// </summary> private void WritePoolB() { UserControl.CheckForIllegalCrossThreadCalls = false; while (richTextBox2.Text.Trim().Length < lenth) { while (Interlocked.Read(ref numberOfusedSpace) == 0) { Thread.Sleep(300); } richTextBox2.AppendText(textBox1.Text); textBox1.Text = ""; Interlocked.Decrement(ref numberOfusedSpace); //Thread.Sleep(1000); } }
Monitor中常用的方法
根据上面的方法可以判断我们需要一个锁信号,一半情况下都是一个空的object类型。是不是可以设置其他类型呢?我们可以再以后空闲的时候尝试一下。
界面样式:
代码:
1 private static object lockobj = new object(); //锁对象 2 int lenth = 0; // 长¡è度¨¨ 3 private void button1_Click(object sender, EventArgs e) 4 { 5 lenth = richTextBox1.Text.Trim().Length; 6 Thread threadReadPoolA = new Thread(ReadPoolA); 7 Thread threadWritePoolB = new Thread(WritePoolB); 8 threadReadPoolA.IsBackground = true; 9 threadWritePoolB.IsBackground = true; 10 threadReadPoolA.Start(); 11 threadWritePoolB.Start(); 12 } 13 private void ReadPoolA() 14 { 15 UserControl.CheckForIllegalCrossThreadCalls = false; 16 string temp = richTextBox1.Text.Trim(); 17 while (richTextBox1.Text.Trim().Length > 0) 18 { 19 try 20 { 21 Monitor.Enter(lockobj); //进入所对象锁定对象 22 textBox1.Text = temp[0].ToString(); 23 temp = temp.Substring(1); 24 richTextBox1.Text = temp; 25 Monitor.Pulse(lockobj); //唤醒在所对象上蹲着的线程告诉他你可以执行了,锁对象的状态已更改。 26 Monitor.Wait(lockobj); //释放锁对象,并且不让自己立刻就获取该对象,但是要等着再次获得对象才能往下执行 27 28 } 29 catch (ThreadInterruptedException ex) 30 { 31 32 MessageBox.Show(ex.ToString()); 33 } 34 finally 35 { 36 Monitor.Exit(lockobj); 37 } 38 } 39 } 40 private void WritePoolB() 41 { 42 UserControl.CheckForIllegalCrossThreadCalls = false; 43 while (richTextBox2.Text.Trim().Length < lenth) 44 { 45 try 46 { 47 Monitor.Enter(lockobj); 48 richTextBox2.AppendText(textBox1.Text); 49 textBox1.Text = ""; 50 Monitor.Pulse(lockobj); 51 Monitor.Wait(lockobj); 52 } 53 catch (ThreadInterruptedException ex) 54 { 55 MessageBox.Show(ex.ToString()); 56 } 57 finally 58 { 59 Monitor.Exit(lockobj); 60 } 61 } 62 } 63 64 private void button2_Click(object sender, EventArgs e) 65 { 66 foreach (Control c in this.Controls) 67 { 68 if (c.GetType().ToString().Contains("TextBox")) 69 { 70 c.Text = ""; 71 } 72 } 73 }
Mutex常用的方法:
界面:
做个功能简单的说明,这个功能是实现同时向1.txt文件写数据。
代码:
1 private void Form1_Load(object sender, EventArgs e) 2 { 3 System.Diagnostics.Process.Start("MetuxA.exe"); 4 Thread thread = new Thread(delegate() 5 { 6 string filepat = @"e:\1.txt"; 7 Mutex mt = new Mutex(false, "MutexRefObj"); 8 while (true) 9 { 10 try 11 { 12 mt.WaitOne(); 13 if (!File.Exists(filepat)) 14 { 15 File.Create(filepat); 16 } 17 string temp = "MetuxB: " + DateTime.Now.ToString() + "\r\n"; 18 File.AppendAllText(filepat, temp); 19 Invoke(new EventHandler(delegate 20 { 21 richTextBox1.AppendText(temp); 22 })); 23 } 24 catch (ThreadInterruptedException ex) 25 { 26 MessageBox.Show(ex.ToString()); 27 } 28 finally 29 { 30 mt.ReleaseMutex(); 31 } 32 Thread.Sleep(500); 33 } 34 }); 35 thread.IsBackground = true; 36 thread.Start(); 37 } 38 } 39 40 41 A B两个类的代码几乎相同。
ps:在这里没有说明lock的使用方法,可能在明天或者是今天晚上我将温习一下lock和跨线程控件访问的控制。