C# 多线程笔记

多线程

启动线程方式

  1. new Thread(), .Start(); 启动线程
  2. Task.Factory.StartNew(); 启动线程
  3. 线程池启动TreadPool.QueueUserWorkItem 启动工作线程
  4. BackgroundWorker .RunWorkerAsync 启动 DoWork 方法
  5. Parallel.Invoke 并行执行 并且会阻塞 主线程,只有当Invoke中的所有任务完毕 才会进行下一步
BackgroundWorker

DoWork事件 触发子线程空间 通过 RunWorkerAsync 方法 触发
ProgressChanged事件 主线程空间 通过 ReportProgress 方法触发
RunWorkerCompleted 事件 主线程空间 DoWork方法执行完成后,自动触发

TreadPool

QueueUserWorkItem 启动一个工作线程
SetMaxThreads 设置线程池的最大线程数
SetMinThreads 设置线程池的最小线程数

Parallel

Invoke - 并行执行 invoke中所有的委托

线程切换

从子线程上下文空间切换到主线程空间,以便更新界面UI

  1. 如果有控件, 可以用控件的 Invoke 方法
  2. 非控件类,可以用 BackgroundWorker 类
  3. SynchronizationContext 的 Send 方法

线程同步信号

在多线程并行时,使用同步信号可以阻塞线程运行,以便按照流程执行代码

  1. 自动同步信号 AutoResetEvent
  2. 手动同步信号 ManualResetEvent
AutoResetEvent 自动重置同步信号事件

此类可以控制在多线程并行情况下,阻塞或依次执行

  • AutoResetEvent(bool initialState) 构造方法,创建一个自动同步信号事件

    • initialState :true 信号是释放的,代表 第一次调用 WaitOne 时不会阻塞线程
    • initialState :false 信号是锁定的,代表 第一次调用 WaitOne 时会阻塞线程
  • **WaitOne **() 阻塞当前线程,直到 使用 Set 方法释放线程

  • Set() 发送一次释放信号,将释放由 WaitOne 方法阻塞的其中一个线程后, 将事件状态重置为锁定

// 创建一个同步信号实例
private static AutoResetEvent event_1 = new AutoResetEvent(false);

/// <summary>
/// 开始测试
/// </summary>
public static void TestAutoResetEvent2()
{
    for (int i = 0; i < 3; i++)
    {
        // 启动三个线程
        var thread = new Thread(UpdateWithLock);
        thread.Start();
    }
}

internal static void ReleaseOnce()
{
    // 发送一次释放信号
    event_1.Set();
}

private static void UpdateWithLock()
{
    string name = Thread.CurrentThread.Name;

    Console.WriteLine("{0} waits on AutoResetEvent #1.", name);
    event_1.WaitOne();
    Console.WriteLine("{0} is released from AutoResetEvent #1.", name);
}
ManualResetEvent 手动同步信号事件

此类可以控制在多线程并行情况下,阻塞或放行全部线程

  • ManualResetEvent (bool initialState) 构造方法,创建一个手动同步信号事件

    • initialState :true 信号是释放的,代表 调用 WaitOne 时不会阻塞线程
    • initialState :false 信号是锁定的,代表 调用 WaitOne 时会阻塞线程
  • **WaitOne **() 如果当前 信号是阻塞的 , 那么就会阻塞当前线程

  • Set() 修改事件状态为释放的,将释放由 WaitOne 方法阻塞的所有线程

  • Reset() 修改事件状态为锁定的, 之后调用的 WaitOne 方法将阻塞线程

 // 创建一个同步信号实例
private static ManualResetEvent event_1 = new ManualResetEvent(true);

/// <summary>
/// 开始测试
/// </summary>
public static void TestManualResetEvent2()
{
    for (int i = 0; i < 3; i++)
    {
        // 启动三个线程
        var thread = new Thread(UpdateWithLock);
        thread.Name = "thread_" + i;
        thread.Start();
    }
}

internal static void ReleaseEvent()
{
    // 将事件状态置为释放
    event_1.Set();
}

internal static void LockEvent()
{
    // 将事件状态置为锁定
    event_1.Reset();
}

private static void UpdateWithLock()
{
    string name = Thread.CurrentThread.Name;

    Console.WriteLine("{0} waits on ManualResetEvent #1.", name);
    event_1.WaitOne();
    Console.WriteLine("{0} is released from ManualResetEvent #1.", name);
}

线程锁

  1. 自旋锁 SpinLock
  2. 互斥锁 Mutex
  3. 混合锁 lock & Monitor
  4. Interlocked
SpinLock 自旋锁

如果需要锁定执行的关键代码量比较少,则SpinLock效率会比lock关键字高

用法:

// 定义
SpinLock _spinlock = new SpinLock();


private static void UpdateWithSpinLock(Data d, int i)
{
    bool lockTaken = false;
    try
    {
        // 锁定资源
        _spinlock.Enter(ref lockTaken);
     
        // 需要锁定执行的代码
        
    }
    finally
    {
        // 释放锁
        if (lockTaken) _spinlock.Exit(false);
    }
}

Mutex 互斥锁

当多个线程需要同时访问某一个共享资源时,Mutex 可以确保一次只有一个线程能使用到该资源

  • bool WaitOne(int timeout) 锁定线程并等待 timeOut 毫秒后,超时
  • void ReleaseMutex() 释放被锁定的资源

用法:

// 创建一个互斥锁对象
private static Mutex mut = new Mutex();


private static void UseResource()
{
    // Wait until it is safe to enter.
    Console.WriteLine("{0} is requesting the mutex",
                      Thread.CurrentThread.Name);
    mut.WaitOne();

    Console.WriteLine("{0} has entered the protected area",
                      Thread.CurrentThread.Name);

    // Place code to access non-reentrant resources here.

    // Simulate some work.
    Thread.Sleep(500);

    Console.WriteLine("{0} is leaving the protected area",
                      Thread.CurrentThread.Name);

    // Release the Mutex.
    mut.ReleaseMutex();
    Console.WriteLine("{0} has released the mutex", Thread.CurrentThread.Name);
}

Monitor 混合锁

说明:

  • 当多个线程需要同时访问某一个共享资源时,Monitor 可以确保一次只有一个线程能使用到该资源
  • Monitor 是全局的,可以从任何上下文来调用
  • Monitor 需要唯一的锁定对象来关联

方法:

  • void Enter(object obj) 锁定线程并等待 timeOut 毫秒后,超时释放
  • void Exit(object obj) 释放被锁定的资源

用法:

// 创建一个互斥锁对象
private static object _lock = new Object();


private static void UseResource()
{
    try
    {
        Monitor.Enter(_lock);
        _queue.Enqueue(d);
    }
    finally
    {
        Monitor.Exit(_lock);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值