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() + "
";
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和跨线程控件访问的控制。

 

原文地址:https://www.cnblogs.com/xiaoch/p/13417960.html