# 线程简例(Thread):
# Demo
Thread thread = new Thread(delegate() {
while (true)
{
Console.WriteLine(DateTime.Now);
Thread.Sleep(1000);
}
});
thread.IsBackground = true;//默认前台,线程默认前台线程,一个进程的标志是所有前台线程的退出
thread.Start();//线程启动
thread.Suspend();//挂起线程
thread.Resume();//挂起线程重启
thread.Abort();//不得已,直接结束,会抛异常
thread.Join(1000);//主线程等待thread子线程执行完成;超时时间1000毫米,超过自动继续执行
thread.Priority = ThreadPriority.Highest;//线程优先级(建议,由操作系统说了算)
Console.WriteLine(thread.ManagedThreadId);//当前子线程id
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);//当前主线程id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 子线程访问主线程
//错误
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Control.CheckForIllegalCrossThreadCalls = false;//只能用于演示阶段,阻止报错
}
private void Button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
textBox1.Text = "dsfds";
});
thread.Start();
}
//正确(子线程访问主线程空间只能使用委托)
报异常处理
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
}
private void Button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
if (textBox1.InvokeRequired)//判断控件是否在该线程上
{
//找到创建该控件的线程,执行委托
textBox1.Invoke(new Action<string>(s=> { this.textBox1.Text = s; }),"123");
}
else
{
textBox1.Text = DateTime.Now.ToString();
}
});
thread.Start();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 线程池(ThreadPool)
ThreadPool.QueueUserWorkItem(s=> { Console.WriteLine(s),"sss"});
1
# 异步线程(IAsyncResult)
内部原理:使一个线程池的线程执行了委托的方法
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Func<int, int, string> delfunc = (a, b) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
return (a + b).ToString();
};
//拿到结果
IAsyncResult result=delfunc.BeginInvoke(3, 4, null, null);
if (result.IsCompleted)
{
}
//EndInvoke方法会阻塞线程,直到异步委托指向完成之后,才能继续往下执行
string s=delfunc.EndInvoke(result);
有回调函数的异步委托
static void Main()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Func<int, int, string> delfunc = (a, b) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
return (a + b).ToString();
};
//入参可以是委托
IAsyncResult result=delfunc.BeginInvoke(3, 4, MyAsyncCallBack, delfunc);
Console.ReadKey();
}
//是异步委托执行完之后,在回来执行的函数
static void MyAsyncCallBack(IAsyncResult ar)
{
//拿到异步委托的结果
AsyncResult result = (AsyncResult)ar;
var del = (Func<int, int, string>)result.AsyncDelegate;
string returnvalue = del.EndInvoke(result);
Console.WriteLine(returnvalue);
//入参
Console.WriteLine($"{result.AsyncState}");
var del= (Func<int, int, string>)result.AsyncState;
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 信号量(Semaphore)
static SemaphoreSlim semLim = new SemaphoreSlim(3); //3表示最多只能有三个线程同时访问
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
new Thread(SemaphoreTest).Start();
}
Console.Read();
}
static void SemaphoreTest()
{
semLim.Wait();
Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "开始执行");
Thread.Sleep(2000);
Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "执行完毕");
semLim.Release();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 异步Task
Console.WriteLine("主线程启动");
//Task.Run启动一个线程
//Task启动的是后台线程,要在主线程中等待后台线程执行完毕,可以调用Wait方法
//Task task = Task.Factory.StartNew(() => { Thread.Sleep(1500); Console.WriteLine("task启动"); });
Task task = Task.Run(() => {
Thread.Sleep(1500);
Console.WriteLine("task启动");
});
Thread.Sleep(300);
task.Wait();
Console.WriteLine("主线程结束");
开启新任务的方法:Task.Run()或者Task.Factory.StartNew(),开启的是后台线程
要在主线程中等待后台线程执行完毕,可以使用Wait方法(会以同步的方式来执行)。不用Wait则会以异步的方式来执行。
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
new Thread(Run1).Start();
}
for (int i = 0; i < 5; i++)
{
Task.Run(() => { Run2(); });
}
}
static void Run1()
{
Console.WriteLine("Thread Id =" + Thread.CurrentThread.ManagedThreadId);
}
static void Run2()
{
Console.WriteLine("Task调用的Thread Id =" + Thread.CurrentThread.ManagedThreadId);
}
Task<TResult>
Console.WriteLine("主线程开始");
//返回值类型为string
Task<string> task = Task<string>.Run(() => {
Thread.Sleep(2000);
return Thread.CurrentThread.ManagedThreadId.ToString();
});
//会等到task执行完毕才会输出;
Console.WriteLine(task.Result);
Console.WriteLine("主线程结束");
async/await
static void Main(string[] args)
{
Console.WriteLine("-------主线程启动-------");
Task<int> task = GetStrLengthAsync();
Console.WriteLine("主线程继续执行");
Console.WriteLine("Task返回的值" + task.Result);
Console.WriteLine("-------主线程结束-------");
}
static async Task<int> GetStrLengthAsync()
{
Console.WriteLine("GetStrLengthAsync方法开始执行");
//此处返回的<string>中的字符串类型,而不是Task<string>
string str = await GetString();
Console.WriteLine("GetStrLengthAsync方法执行结束");
return str.Length;
}
static Task<string> GetString()
{
//Console.WriteLine("GetString方法开始执行")
return Task<string>.Run(() =>
{
Thread.Sleep(2000);
return "GetString的返回值";
});
}
async用来修饰方法,表明这个方法是异步的,声明的方法的返回类型必须为:void,Task或Task<TResult>。
await必须用来修饰Task或Task<TResult>,而且只能出现在已经用async关键字修饰的异步方法中。通常情况下,async/await成对出现才有意义,
那么await的作用是什么呢?
可以从字面上理解,上面提到task.wait可以让主线程等待后台线程执行完毕,await和wait类似,同样是等待,等待Task<string>.Run()开始的后台线程执行完毕,不同的是await不会阻塞主线程,只会让GetStrLengthAsync方法暂停执行
挂起:一般是主动的,由系统或程序发出,甚至于辅存中去。(不释放CPU,可能释放内存,放在外存)
阻塞:一般是被动的,在抢占资源中得不到资源,被动的挂起在内存,等待某种资源或信号量(即有了资源)将他唤醒。(释放CPU,不释放内存)
Parallel
Stopwatch watch1 = new Stopwatch();
watch1.Start();
for (int i = 1; i <= 10; i++)
{
Console.Write(i + ",");
Thread.Sleep(1000);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed);
Stopwatch watch2 = new Stopwatch();
watch2.Start();
//会调用线程池中的线程
Parallel.For(1, 11, i =>
{
Console.WriteLine(i + ",线程ID:" + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000);
});
watch2.Stop();
Console.WriteLine(watch2.Elapsed);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# 进程概念
进程就是一个软件
Process p;//实例化一个Process对象
p = Process.Start(@"E:\1.txt");//要开启的进程(或 要启用的程序),括号内为绝对路径
p.Kill();//结束进程
直接用Thread会开启5个线程,用Task(用了线程池)开启了3个!
补充c#
lock()//后面加一个引用类型的实例
{
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10