开放的编程资料库

当前位置:我爱分享网 > C#教程 > 正文

C#线程

在本文中,我们使用C#中的线程。

进程是计算机中运行的程序实例。当进程启动时,公共语言运行库(CLR)会自动创建一个单一的前台线程来执行应用程序代码。一个进程可以运行多个线程。一个线程是一个程序唯一的执行路径。

在C#中,Thread类表示一个线程。它创建并控制线程、设置其优先级并获取其状态。Thread类是System.Threading命名空间的一部分。

进程和线程都是独立的执行序列。下表总结了进程和线程的区别:

td>孩子可以变成僵尸

tr>

Process Thread
进程在单独的内存中运行(进程隔离) 线程共享内存
使用更多内存 使用更少内存
不可能变成僵尸
更多开销 更少开销
创建和销毁速度较慢 创建和销毁速度较快
更易于编码和调试 可以成为更难编码和调试

C#线程启动

Start方法启动一个线程。

Console.WriteLine("main started");
var id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"main id: {id}");

var t = new Thread(task);
t.Start();

Console.WriteLine("main finished");

void task()
{
    Console.WriteLine("thread started");
    var id = Thread.CurrentThread.ManagedThreadId;
    Console.WriteLine($"thread id: {id}");
}

创建一个新线程,然后使用Start启动。

Console.WriteLine("main started");

主程序本身就是一个单独的执行线程。

var id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"main id: {id}");

Thread.CurrentThread.ManagedThreadId获取当前托管线程的唯一标识符。

var t = new Thread(task);

创建了一个新的线程。我们传递对在线程中执行的函数的引用。

t.Start();

线程启动。

void task()
{
    Console.WriteLine("thread started");
    var id = Thread.CurrentThread.ManagedThreadId;
    Console.WriteLine($"thread id: {id}");
}

在函数内部,我们获取并打印线程ID。

$ dotnet run
main started
main id: 1
main finished
thread started
thread id: 4

注意主线程在其他线程之前完成。程序等待线程完成。

C#线程传递参数

在下一个示例中,我们将展示如何将参数传递给线程。

int n = 5;
string word = "falcon";

// var t = new Thread(() => { for (int i = 0; i < n; i++) Console.WriteLine(word); });
var t = new Thread(() => repeat(n, word));
t.Start();

void repeat(int n, string word)
{
    for (int i = 0; i < n; i++)
    {
        Console.WriteLine(word);
    }
}

线程打印一个单词n次。我们将单词和数字作为参数传递。

var t = new Thread(() => repeat(n, word));

线程采用lambda表达式,其中repeat函数使用两个参数调用。

$ dotnet run
falcon
falcon
falcon
falcon
falcon

C#线程.睡眠

Tread.Sleep方法将当前线程挂起指定的毫秒数。该方法对调试和测试很有用。

常用于模拟长时间运行的任务。

for (int i = 0; i < 5; i++)
{
    var n = new Random().Next(500, 1500);

    var t = new Thread(() => task(n));
    t.Start();
}

void task(int n)
{
    var id = Thread.CurrentThread.ManagedThreadId;

    Console.WriteLine($"thread id: {id} started");
    Thread.Sleep(n);
    Console.WriteLine($"thread id: {id} finished in {n} ms");
}

在程序中,我们创建了5个线程,它们休眠的时间是随机的毫秒数。

var n = new Random().Next(500, 1500);

我们创建一个介于500和1500之间的随机数。

var t = new Thread(() => task(n));
t.Start();

我们将随机数传递给新创建的线程。

void task(int n)
{
    var id = Thread.CurrentThread.ManagedThreadId;

    Console.WriteLine($"thread id: {id} started");
    Thread.Sleep(n);
    Console.WriteLine($"thread id: {id} finished in {n} ms");
}

在线程内运行的函数使用Tread.Sleep暂停执行n毫秒。

$ dotnet run
thread id: 5 started
thread id: 6 started
thread id: 4 started
thread id: 7 started
thread id: 8 started
thread id: 5 finished in 822 ms
thread id: 8 finished in 891 ms
thread id: 6 finished in 902 ms
thread id: 4 finished in 946 ms
thread id: 7 finished in 1113 ms

C#前台&后台线程

有两个线程之王:前台和后台。后台线程不会阻止进程终止。当属于一个进程的所有前台线程都终止时,CLR将结束该进程。

默认线程是前台线程。我们使用IsBackground属性将线程更改为后台线程。

Console.WriteLine("started main");

for (var i = 0; i < 5; i++)
{
    var rn = new Random().Next(500, 1500);
    var t = new Thread(() => task(rn));
    t.IsBackground = true;
    t.Start();

}

void task(int n)
{
    Thread.Sleep(n);
    var id = Thread.CurrentThread.ManagedThreadId;
    Console.WriteLine($"{id} finished in {n} ms");
}

Console.WriteLine("finished main");

在示例中,我们创建了一个主程序线程和五个后台线程。

$ dotnet run
started main
finished main

一旦唯一的前台线程完成,所有其他后台线程都终止,程序结束。后台线程没有时间运行。

$ dotnet run
started main
finished main
8 finished in 572 ms
4 finished in 770 ms
7 finished in 772 ms
6 finished in 1145 ms
5 finished in 1397 ms

当我们调用t.IsBackground=true;行时,我们创建了前台线程。然后主线程等待其他前台线程完成并运行五个线程。

C#线程连接

Join方法会阻塞调用线程,直到指定的线程终止。

Console.WriteLine("main started");
var id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"main id: {id}");

Thread[] threads = new Thread[5];

for (int i = 0; i < 5; i++)
{
    var n = new Random().Next(500, 1500);
    threads[i] =  new Thread(() => task(n));
}

foreach (var thread in threads)
{
    thread.Start();
}

foreach (var thread in threads)
{
    thread.Join();
}

void task(int n)
{
    var id = Thread.CurrentThread.ManagedThreadId;

    Console.WriteLine($"thread id: {id} started");
    Thread.Sleep(n);
    Console.WriteLine($"thread id: {id} finished in {n} ms");
}

Console.WriteLine("main finished");

在这个程序中,主线程等待所有其他线程完成。

Thread[] threads = new Thread[5];

for (int i = 0; i < 5; i++)
{
    var n = new Random().Next(500, 1500);
    threads[i] =  new Thread(() => task(n));
}

我们创建了一个包含五个线程的数组,这些线程将休眠随机数毫秒。

foreach (var thread in threads)
{
    thread.Start();
}

首先,我们启动所有五个线程。

foreach (var thread in threads)
{
    thread.Join();
}

使用Join,我们会阻塞主线程,直到数组中的所有五个线程都完成。

$ dotnet run
main started
main id: 1
thread id: 4 started
thread id: 5 started
thread id: 6 started
thread id: 7 started
thread id: 8 started
thread id: 7 finished in 802 ms
thread id: 4 finished in 1080 ms
thread id: 8 finished in 1354 ms
thread id: 6 finished in 1358 ms
thread id: 5 finished in 1461 ms
main finished

带秒表的C#线程

使用秒表,我们可以准确地测量经过的时间。

using System.Diagnostics;

Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

var sw = new Stopwatch();
sw.Start();

Thread[] threads = new Thread[10];

for (var i = 0; i < 10; i++)
{
    var t = new Thread(() =>
    {
        var id = Thread.CurrentThread.ManagedThreadId;
        var r = new Random().Next(500, 1500);
        Thread.Sleep(r);
        Console.WriteLine($"{id} finished in {r} ms");
    }
);
    threads[i] = t;
}

foreach (var t in threads)
{
    t.Start();
}

foreach (var t in threads)
{
    t.Join();
}

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;

Console.WriteLine($"elapsed: {elapsed} ms");

我们创建了十个运行随机毫秒数的线程。主线程等待所有其他线程完成并计算经过的时间。

var sw = new Stopwatch();
sw.Start();

我们创建了Stopwatch并运行它。

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;

Console.WriteLine($"elapsed: {elapsed} ms");

最后,我们计算经过的时间并打印结果。

$ dotnet run
1
13 finished in 539 ms
4 finished in 547 ms
9 finished in 617 ms
6 finished in 782 ms
8 finished in 787 ms
7 finished in 917 ms
10 finished in 968 ms
12 finished in 1170 ms
5 finished in 1468 ms
11 finished in 1488 ms
elapsed: 1488 ms

程序运行的时间与最长的线程一样长。

在本文中,我们使用了C#中的线程。

列出所有C#教程。

未经允许不得转载:我爱分享网 » C#线程

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏