📜  C#多线程(1)

📅  最后修改于: 2023-12-03 15:30:19.344000             🧑  作者: Mango

C# 多线程

C# 是一种支持多线程的编程语言,允许程序员创建多个执行路径来同时执行代码,从而实现并发性。通过多线程,可以提高程序的性能和响应性,以及利用多核心 CPU 的资源。

创建线程

在 C# 中,可以使用 Thread 类来创建线程。下面是一个创建线程的例子:

using System;
using System.Threading;

public class Program {
    public static void Main() {
        Thread t = new Thread(new ThreadStart(DoWork));
        t.Start();
        Console.WriteLine("Main thread exits.");
    }

    static void DoWork() {
        Console.WriteLine("Worker thread started.");
        Thread.Sleep(1000);
        Console.WriteLine("Worker thread ends.");
    }
}

在上述例子中,我们创建了一个名为 t 的线程对象,并将其初始化为一个 DoWork 函数的引用。然后我们调用 t.Start() 方法启动线程。最后我们输出一些文本来表示程序已经执行完毕。

DoWork 函数是在一个新的线程中执行的。我们使用 Thread.Sleep() 函数来模拟一些长时间运行的操作。

线程同步

多线程程序的一个重要问题是如何协调多个线程的访问共享资源。如果多个线程同时访问同一个资源,可能会导致竞态条件(race condition)或死锁(deadlock)。

C# 中有多种方法来管理线程同步,其中两种最常用的是使用锁和信号量(Semaphore)。

锁是一种最基本的线程同步机制。锁定一个对象意味着只有一个线程可以访问该对象。其他线程需要等待当前线程释放锁才能访问对象。

下面是一个使用锁的例子:

using System;
using System.Threading;

public class Program {
    static object lockObj = new object();

    public static void Main() {
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(new ThreadStart(DoWork));
            t.Start(i);
        }
        Console.ReadLine();
    }

    static void DoWork(object id) {
        lock (lockObj) {
            Console.WriteLine("Thread {0} starts.", id);
            Thread.Sleep(1000);
            Console.WriteLine("Thread {0} ends.", id);
        }
    }
}

在上述例子中,我们创建了 lockObj 对象作为锁。在 DoWork 函数中,我们将锁定 lockObj 对象以确保只有一个线程可以进入临界区域。其他线程需要等待当前线程释放锁才能进入。

信号量

信号量是另一种常用的线程同步机制。信号量可以控制同一时间可以有多少个线程访问共享资源。在 C# 中,可以使用 Semaphore 类来实现信号量。

下面是一个使用信号量的例子:

using System;
using System.Threading;

public class Program {
    static Semaphore sem = new Semaphore(3, 3);

    public static void Main() {
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(new ThreadStart(DoWork));
            t.Start(i);
        }
        Console.ReadLine();
    }

    static void DoWork(object id) {
        sem.WaitOne();
        Console.WriteLine("Thread {0} starts.", id);
        Thread.Sleep(1000);
        Console.WriteLine("Thread {0} ends.", id);
        sem.Release();
    }
}

在上述例子中,我们创建了一个初始值为 3 的信号量 sem。在 DoWork 函数中,我们使用 sem.WaitOne() 方法来获取信号量。如果当前信号量计数为 0,线程会进入阻塞状态。如果当前信号量计数大于 0,线程会减少信号量计数并继续执行。在临界区域结束后,我们使用 sem.Release() 方法来释放信号量。

异步编程

异步编程是另一种常用的多线程技术。异步编程可以帮助减少线程阻塞时间,并提高程序的响应性。在 C# 中,可以使用 asyncawait 关键字来实现异步编程。

下面是一个使用异步编程的例子:

using System;
using System.Threading.Tasks;

public class Program {
    public static async Task Main() {
        Console.WriteLine("Main thread starts.");
        await DoWorkAsync();
        Console.WriteLine("Main thread ends.");
    }

    static async Task DoWorkAsync() {
        Console.WriteLine("Worker thread starts.");
        await Task.Delay(1000);
        Console.WriteLine("Worker thread ends.");
    }
}

在上述例子中,我们将 Main 函数定义为异步函数,并使用 await 关键字等待 DoWorkAsync 函数完成。在 DoWorkAsync 函数中,我们使用 Task.Delay() 方法来模拟长时间运行的操作。由于 Task.Delay() 是异步方法,该方法不会阻塞线程。

总结

C# 是一个功能强大的多线程编程语言,提供了多种机制来实现线程同步和异步编程。通过使用这些技术,可以提高程序的性能、响应性和可靠性。