C#之多线程与 Thread.Sleep休眠

C# 多线程编程全面教程

可以让多个方法同时运行
1.线程里如何放方法
2.启动线程: thread1.Start();
3.等待线程结束: thread1.Join();
Thread.Sleep休眠
休眠的用处1:在while(true)循环中加上Sleep(2)休眠2ms,可以大大缓解cpu资源

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace C_之多线程
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        /// <summary>
        /// 多线程:Thread
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            // 多线程
            Thread thread = new Thread(Fun1);
            // 启动线程
            thread.Start();

            // 多线程
            Thread thread2 = new Thread(Fun2);
            // 启动线程
            thread2.Start();

            // 等待线程结束
            thread.Join();
            thread2.Join();

            // 必须在这个两个方法执行之后,再执行
            MessageBox.Show("多线程");

        }

        public void Fun1()
        {
            for (int i = 0; i < 5; i++)
            {
                // 睡眠 1s
                Thread.Sleep(1000);
                Console.WriteLine("第一个函数");
            }
        }

        public void Fun2()
        {
            for (int i = 0; i < 5; i++)
            {
                // 睡眠 1s
                Thread.Sleep(1000);
                Console.WriteLine("第二个函数");
            }
        }
    }
}

多线程编程是现代C#开发中的核心技能之一,它允许开发者充分利用多核处理器的性能优势,创建响应迅速且高效的应用程序。本教程将从基础到高级,全面介绍C#中的多线程编程技术。

一、多线程基础概念

1.1 为什么需要多线程?

  • 提高性能:利用多核CPU并行执行任务
  • 响应性:保持UI界面流畅,后台执行耗时操作
  • 资源利用率:同时处理I/O密集型和CPU密集型任务
  • 模块化:将复杂任务分解为独立执行的单元

1.2 线程基础术语

  • 线程(Thread):操作系统执行程序的最小单位
  • 进程(Process):程序在内存中的运行实例
  • 并发(Concurrency):多个任务交替执行(单核CPU)
  • 并行(Parallelism):多个任务同时执行(多核CPU)
  • 同步(Synchronization):协调线程执行顺序
  • 异步(Asynchronous):非阻塞的执行方式

二、C#多线程基础实现

2.1 Thread类(传统方式)

using System;
using System.Threading;

class ThreadExample
{
    static void Main()
    {
        // 创建并启动线程
        Thread thread1 = new Thread(DoWork);
        thread1.Name = "WorkerThread1";
        thread1.Start(); // 启动线程
        
        // 带参数的线程
        Thread thread2 = new Thread(() => PrintMessage("Hello from Thread 2!"));
        thread2.Start();
        
        // 主线程继续执行
        Console.WriteLine($"Main thread {Thread.CurrentThread.ManagedThreadId} working...");
        
        // 等待线程完成(不推荐在实际应用中使用,会阻塞主线程)
        thread1.Join();
        thread2.Join();
        
        Console.WriteLine("All threads completed.");
    }
    
    static void DoWork()
    {
        Console.WriteLine($"Thread {Thread.CurrentThread.Name} started on {Thread.CurrentThread.ManagedThreadId}");
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"Working... {i}");
            Thread.Sleep(500); // 模拟工作
        }
        Console.WriteLine($"Thread {Thread.CurrentThread.Name} completed.");
    }
    
    static void PrintMessage(string message)
    {
        Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}: {message}");
    }
}

2.2 ThreadPool(线程池)

using System;
using System.Threading;

class ThreadPoolExample
{
    static void Main()
    {
        // 排队执行工作项
        ThreadPool.QueueUserWorkItem(DoBackgroundWork, "Task 1");
        ThreadPool.QueueUserWorkItem(DoBackgroundWork, "Task 2");
        
        // 使用lambda表达式
        ThreadPool.QueueUserWorkItem(state => 
        {
            Console.WriteLine($"Lambda task: {state}");
            Thread.Sleep(1000);
        }, "Lambda Task");
        
        Console.WriteLine("Main thread continuing...");
        
        // 等待线程池完成(实际中通常不需要,线程池是长期运行的)
        Thread.Sleep(3000);
    }
    
    static void DoBackgroundWork(object state)
    {
        Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} processing {state}");
        Thread.Sleep(500); // 模拟工作
        Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} completed {state}");
    }
}

三、Task Parallel Library (TPL)

3.1 Task类(推荐方式)

using System;
using System.Threading.Tasks;

class TaskExample
{
    static async Task Main()
    {
        Console.WriteLine($"Main thread started on {Thread.CurrentThread.ManagedThreadId}");
        
        // 创建并启动Task
        Task task1 = Task.Run(() => 
        {
            Console.WriteLine($"Task 1 started on {Thread.CurrentThread.ManagedThreadId}");
            Thread.Sleep(1000);
            Console.WriteLine($"Task 1 completed on {Thread.CurrentThread.ManagedThreadId}");
            return "Result from Task 1";
        });
        
        // 带参数的Task
        Task<string> task2 = Task.Run(() => ProcessData("Data for Task 2"));
        
        // 等待所有Task完成并获取结果
        string[] results = await Task.WhenAll(task1, task2);
        
        Console.WriteLine("All tasks completed:");
        foreach (var result in results)
        {
            Console.WriteLine(result);
        }
        
        // 继续执行主线程
        Console.WriteLine($"Main thread continuing on {Thread.CurrentThread.ManagedThreadId}");
    }
    
    static string ProcessData(string input)
    {
        Console.WriteLine($"Processing {input} on {Thread.CurrentThread.ManagedThreadId}");
        Thread.Sleep(1500);
        return $"Processed: {input}";
    }
}

3.2 Parallel类(并行循环)

using System;
using System.Threading.Tasks;

class ParallelExample
{
    static void Main()
    {
        Console.WriteLine($"Main thread {Thread.CurrentThread.ManagedThreadId}");
        
        // 并行For循环
        Parallel.For(0, 10, i => 
        {
            Console.WriteLine($"Parallel.For: Processing {i} on {Thread.CurrentThread.ManagedThreadId}");
            Thread.Sleep(100); // 模拟工作
        });
        
        Console.WriteLine("Parallel.For completed");
        
        // 并行ForEach循环
        string[] data = { "Apple", "Banana", "Cherry", "Date" };
        Parallel.ForEach(data, item => 
        {
            Console.WriteLine($"Parallel.ForEach: Processing {item} on {Thread.CurrentThread.ManagedThreadId}");
            Thread.Sleep(200); // 模拟工作
        });
        
        Console.WriteLine("Parallel.ForEach completed");
        
        // 带取消支持的并行循环
        var cts = new CancellationTokenSource();
        cts.CancelAfter(1000); // 1秒后取消
        
        try
        {
            Parallel.For(0, 20, new ParallelOptions
            {
                CancellationToken = cts.Token,
                MaxDegreeOfParallelism = 2 // 限制最大并行度
            }, i => 
            {
                Console.WriteLine($"Cancellable loop: {i}");
                Thread.Sleep(300); // 模拟工作
            });
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("Loop was cancelled");
        }
    }
}

四、线程同步与通信

4.1 锁机制(Lock)

using System;
using System.Threading;

class LockExample
{
    private static readonly object _lockObj = new object();
    private static int _counter = 0;
    
    static void Main()
    {
        var threads = new Thread[5];
        for (int i = 0; i < threads.Length; i++)
        {
            threads[i] = new Thread(IncrementCounter);
            threads[i].Start();
        }
        
        foreach (var thread in threads)
        {
            thread.Join();
        }
        
        Console.WriteLine($"Final counter value: {_counter}");
    }
    
    static void IncrementCounter()
    {
        for (int i = 0; i < 10000; i++)
        {
            // 使用lock确保线程安全
            lock (_lockObj)
            {
                _counter++;
            }
        }
    }
}

4.2 Monitor类(更灵活的锁)

using System;
using System.Threading;

class MonitorExample
{
    private static readonly object _lockObj = new object();
    private static bool _isReady = false;
    
    static void Main()
    {
        var worker = new Thread(WorkerThread);
        worker.Start();
        
        // 主线程准备数据
        Thread.Sleep(2000); // 模拟准备时间
        
        lock (_lockObj)
        {
            _isReady = true;
            Monitor.Pulse(_lockObj); // 通知等待的线程
        }
        
        worker.Join();
    }
    
    static void WorkerThread()
    {
        lock (_lockObj)
        {
            while (!_isReady)
            {
                Console.WriteLine("Worker waiting for data...");
                Monitor.Wait(_lockObj); // 释放锁并等待
            }
            
            Console.WriteLine("Worker received notification, processing data...");
        }
    }
}

4.3 Mutex(跨进程同步)

using System;
using System.Threading;

class MutexExample
{
    private static Mutex _mutex = new Mutex(false, "Global\\MyAppMutex");
    
    static void Main()
    {
        Console.WriteLine("Attempting to acquire mutex...");
        
        // 尝试获取互斥体
        if (_mutex.WaitOne(TimeSpan.FromSeconds(5), false))
        {
            try
            {
                Console.WriteLine("Mutex acquired, performing critical operation...");
                Thread.Sleep(3000); // 模拟关键操作
            }
            finally
            {
                _mutex.ReleaseMutex();
                Console.WriteLine("Mutex released");
            }
        }
        else
        {
            Console.WriteLine("Could not acquire mutex, another instance may be running");
        }
    }
}

4.4 Semaphore(信号量)

using System;
using System.Threading;

class SemaphoreExample
{
    private static Semaphore _semaphore = new Semaphore(3, 3); // 初始3,最大3
    
    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            new Thread(Worker).Start(i);
        }
        
        Console.ReadLine(); // 保持主线程运行
    }
    
    static void Worker(object id)
    {
        Console.WriteLine($"Worker {id} waiting for semaphore...");
        
        _semaphore.WaitOne(); // 获取信号量
        Console.WriteLine($"Worker {id} entered the critical section");
        
        Thread.Sleep(1000); // 模拟工作
        
        Console.WriteLine($"Worker {id} leaving the critical section");
        _semaphore.Release(); // 释放信号量
    }
}

4.5 事件等待句柄(EventWaitHandle)

using System;
using System.Threading;

class EventWaitHandleExample
{
    private static EventWaitHandle _waitHandle = new AutoResetEvent(false);
    
    static void Main()
    {
        var worker = new Thread(WorkerThread);
        worker.Start();
        
        Console.WriteLine("Main thread working...");
        Thread.Sleep(3000); // 模拟工作
        
        Console.WriteLine("Main thread signaling worker...");
        _waitHandle.Set(); // 触发事件
        
        worker.Join();
    }
    
    static void WorkerThread()
    {
        Console.WriteLine("Worker thread waiting for signal...");
        _waitHandle.WaitOne(); // 等待事件
        
        Console.WriteLine("Worker thread received signal, performing task...");
        Thread.Sleep(2000); // 模拟工作
    }
}

五、高级多线程模式

5.1 生产者-消费者模式

using System;
using System.Collections.Concurrent;
using System.Threading;

class ProducerConsumerExample
{
    private static BlockingCollection<int> _queue = new BlockingCollection<int>(100);
    
    static void Main()
    {
        var producerThread = new Thread(Producer);
        var consumerThread = new Thread(Consumer);
        
        producerThread.Start();
        consumerThread.Start();
        
        producerThread.Join();
        consumerThread.Join();
    }
    
    static void Producer()
    {
        Random random = new Random();
        for (int i = 0; i < 20; i++)
        {
            int item = random.Next(100);
            _queue.Add(item);
            Console.WriteLine($"Produced: {item}");
            Thread.Sleep(random.Next(100, 500)); // 模拟生产时间
        }
        
        _queue.CompleteAdding(); // 标记生产完成
    }
    
    static void Consumer()
    {
        foreach (var item in _queue.GetConsumingEnumerable())
        {
            Console.WriteLine($"Consumed: {item}");
            Thread.Sleep(800); // 模拟消费时间
        }
        
        Console.WriteLine("Consumer finished");
    }
}

5.2 线程本地存储(ThreadLocal)

using System;
using System.Threading;

class ThreadLocalExample
{
    private static ThreadLocal<int> _threadLocalCounter = new ThreadLocal<int>(() => 
    {
        Random random = new Random();
        return random.Next(1000, 9999); // 每个线程有自己的随机种子
    });
    
    static void Main()
    {
        var threads = new Thread[3];
        for (int i = 0; i < threads.Length; i++)
        {
            threads[i] = new Thread(Worker);
            threads[i].Start();
        }
        
        foreach (var thread in threads)
        {
            thread.Join();
        }
    }
    
    static void Worker()
    {
        int counter = _threadLocalCounter.Value;
        Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} counter: {counter}");
        
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: {counter} * {i} = {counter * i}");
            Thread.Sleep(100);
        }
    }
}

5.3 异步编程模式(async/await)

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;

class AsyncExample
{
    static async Task Main()
    {
        Console.WriteLine($"Main thread started on {Thread.CurrentThread.ManagedThreadId}");
        
        // 并行下载多个URL
        string[] urls = {
            "https://example.com",
            "https://microsoft.com",
            "https://github.com"
        };
        
        Task<string>[] downloadTasks = urls.Select(url => DownloadPageAsync(url)).ToArray();
        string[] results = await Task.WhenAll(downloadTasks);
        
        Console.WriteLine("All downloads completed:");
        foreach (var result in results)
        {
            Console.WriteLine($"Downloaded {result.Length} bytes");
        }
        
        Console.WriteLine($"Main thread continuing on {Thread.CurrentThread.ManagedThreadId}");
    }
    
    static async Task<string> DownloadPageAsync(string url)
    {
        using (HttpClient client = new HttpClient())
        {
            Console.WriteLine($"Starting download from {url} on {Thread.CurrentThread.ManagedThreadId}");
            string content = await client.GetStringAsync(url);
            Console.WriteLine($"Completed download from {url} on {Thread.CurrentThread.ManagedThreadId}");
            return content;
        }
    }
}

六、多线程最佳实践

6.1 设计原则

  1. 避免共享状态:尽可能减少线程间共享的数据
  2. 最小化临界区:锁定的代码块应尽可能小
  3. 避免死锁:保持锁获取顺序一致,使用超时
  4. 考虑线程亲和性:某些操作可能需要特定线程执行(如UI线程)
  5. 使用线程安全集合:如ConcurrentQueueConcurrentDictionary

6.2 性能考虑

  1. 线程池使用:对于短期任务,优先使用线程池
  2. 并行度控制:根据CPU核心数调整并行度
  3. I/O密集型 vs CPU密集型:不同类型任务需要不同策略
  4. 任务取消:提供优雅的取消机制
  5. 异常处理:确保线程中的异常被正确捕获和处理

6.3 常见陷阱

  1. 竞态条件:多个线程同时修改共享数据
  2. 死锁:两个或多个线程互相等待对方释放资源
  3. 活锁:线程不断重试但无法前进
  4. 饥饿:某些线程无法获得执行机会
  5. 线程泄漏:未正确终止的线程

6.4 调试技巧

  1. 使用Visual Studio调试器:并行堆栈窗口、并行任务窗口
  2. 日志记录:记录线程ID和操作
  3. 最小化测试:隔离问题线程
  4. 使用性能分析器:识别线程瓶颈

七、完整示例:并行文件处理

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading.Tasks;

class ParallelFileProcessor
{
    static async Task Main()
    {
        string directory = @"C:\Temp\Files"; // 替换为实际目录
        string outputFile = @"C:\Temp\Results\summary.txt";
        
        try
        {
            Console.WriteLine("Starting parallel file processing...");
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();
            
            // 获取所有文件
            string[] files = Directory.GetFiles(directory, "*.txt");
            Console.WriteLine($"Found {files.Length} files to process");
            
            // 并行处理文件
            var results = new ConcurrentBag<string>();
            
            ParallelOptions options = new ParallelOptions
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount * 2, // 限制并行度
                CancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(5)).Token // 5分钟超时
            };
            
            await Task.Run(() => 
            {
                Parallel.ForEach(files, options, file => 
                {
                    try
                    {
                        string content = File.ReadAllText(file);
                        int wordCount = CountWords(content);
                        string result = $"File: {Path.GetFileName(file)}, Words: {wordCount}";
                        results.Add(result);
                        Console.WriteLine(result);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Error processing {file}: {ex.Message}");
                    }
                });
            });
            
            // 保存结果
            Directory.CreateDirectory(Path.GetDirectoryName(outputFile));
            File.WriteAllLines(outputFile, results);
            
            stopwatch.Stop();
            Console.WriteLine($"Processing completed in {stopwatch.ElapsedMilliseconds}ms");
            Console.WriteLine($"Results saved to {outputFile}");
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("Processing was cancelled due to timeout");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
    
    static int CountWords(string text)
    {
        // 简单单词计数(实际可能需要更复杂的逻辑)
        return text.Split(new[] { ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries).Length;
    }
}

八、总结

C#提供了丰富的多线程编程工具,从传统的Thread类到现代的Task Parallel Libraryasync/await模式。关键要点

  1. 选择正确的工具

    • 简单后台任务:ThreadPoolTask.Run
    • 并行循环:Parallel.For/Parallel.ForEach
    • 异步I/O:async/await
    • 复杂同步需求:Monitor/Mutex/Semaphore
  2. 同步策略

    • 优先使用不可变数据
    • 必须共享时使用线程安全集合
    • 临界区尽可能小
    • 考虑使用lockInterlocked
  3. 现代C#多线程

    • async/await是异步编程的首选方式
    • ValueTask可以减少分配(高频率场景)
    • Channel提供线程安全的生产者-消费者队列
  4. 调试与优化

    • 使用性能分析器识别瓶颈
    • 监控线程创建和上下文切换
    • 考虑使用ParallelOptions调整并行度

通过合理使用这些技术,你可以构建出高效、响应迅速且线程安全的C#应用程序。多线程编程虽然复杂,但掌握这些模式和最佳实践将使你能够充分利用现代硬件的能力。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值