多线程调用中的注意事项

注意:

1、不管是哪种多线程方法,在线程中访问共享资源的时候一定要用lock锁起来!不然会由于冲突产生各种奇奇怪怪的问题。

2、委托(含拉姆达表达式)中调用的方法,其参数如果是变量,它的值取决于运行的那一刻内存里的值。如果希望在创建任务的时候值是固定的,必须用object参数state作为创建任务的状态,把值给进去。(也就是《编译原理》中的“编译时”和“运行时”的差别)

3、而对于委托的begininvoke方法,里面的回调参数,是IAsyncResult类型。需要用它的“AsyncState”属性(object类型)获取传入的的内容(这一点跟代码提示的内容不一样)。

如果不太理解,看例子:

对于第一点

 1 public partial class Form1 : Form
 2     {
 3         public Form1()
 4         {
 5             InitializeComponent();
 6             pBar1.Maximum = 200;
 7             pBar1.Step = 1;
 8             CheckForIllegalCrossThreadCalls = false;
 9         }
10 
11         private void button1_Click(object sender, EventArgs e)
12         {
13             for (int i = 1; i <=100; i++)
14             {
15                 for (int j = 80; j <=81; j++)
16                 {
17                     ThreadPool.QueueUserWorkItem(tryconnect, new MyData(i, j));
18                 }
19             }
20         }
21         void tryconnect(object o)
22         {
23             int i, j;
24             i = ((MyData)o).x;
25             j = ((MyData)o).y;
26             TcpClient tcp = new TcpClient();
27             IAsyncResult async = tcp.BeginConnect(IPAddress.Parse($"192.168.1.{i}"), j, null, null);
28             async.AsyncWaitHandle.WaitOne(1000);
29             lock(listBox1)
30             if (async.IsCompleted)
31             {
32                 listBox1.Items.Add($"192.168.1.{i}:{j} is open.");
33             }
34             else
35             {
36                 listBox1.Items.Add($"192.168.1.{i}:{j} is closed.");
37             }
38             //pBar1.PerformStep();
39             tcp.Close();
40             lock (pBar1)
41             pBar1.PerformStep();
42         }
43 
44         private void button2_Click(object sender, EventArgs e)
45         {
46             Close();
47         }
48     }
49     class MyData
50     {
51         public int x, y;
52         public MyData(int a,int b)
53         {
54             x = a;
55             y = b;
56         }
57     }

对于这种密集的异步线程,再调用异步tcp连接,如果没有第29行的lock,在vs下调试时关闭窗口的时候就有很大概率出现下图的错误:

 争夺资源越激烈概率越大,像代码中那样200次连接,已经是必然发生了。4次连接,大概25%左右发生概率。

编译完成的应用直接打开,退出的时候会出现一个错误框,一闪而逝,不注意看不到。

貌似不影响用户使用,但毕竟是隐患。

原文地址:https://www.cnblogs.com/wanjinliu/p/12766141.html