# 线程简例(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
# 子线程访问主线程
//错误
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
# 线程池(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
# 信号量(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
# 异步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

# 进程概念

进程就是一个软件
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