You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

255 lines
8.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace MultiThreadingStudy.Core
{
/// <summary>
/// 线程本地存储 执行器
/// </summary>
public class ThreadLocalStorage
{
/// <summary>
/// 不使用线程本地存储
/// </summary>
public static void Run()
{
var demo = new Computer();
var thread_a = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_a" };
var thread_b = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_b" };
thread_a.Start();
thread_b.Start();
thread_a.Join();
thread_b.Join();
//调用线程:[主线程|内核线程] 共享字段的值。不加处理的话,可能小于多线程调用次数之和。
Console.WriteLine("调用线程的共享变量值 = " + Computer.TotalCount);
}
/// <summary>
/// 使用 ThreadStatic 特性
/// </summary>
public static void UseThreadStaticAttribute()
{
var demo = new ThreadStaticComputer();
var thread_a = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_a" };
var thread_b = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_b" };
thread_a.Start();
thread_b.Start();
thread_a.Join();
thread_b.Join();
//调用线程:[主线程|内核线程] 共享字段的值。不加处理的话,可能小于多线程调用次数之和。
Console.WriteLine("调用线程的共享变量值 = " + Computer.TotalCount);
}
/// <summary>
/// 使用数据槽
/// </summary>
public static void UseDataSlot()
{
var demo = new DataSlotComputer();
var thread_a = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_a" };
var thread_b = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_b" };
thread_a.Start();
thread_b.Start();
thread_a.Join();
thread_b.Join();
//调用线程:[主线程|内核线程] 共享字段的值。不加处理的话,可能小于多线程调用次数之和。
Console.WriteLine("调用线程的共享变量值 = " + Computer.TotalCount);
}
/// <summary>
/// 使用 ThreadLocal 泛型类
/// </summary>
public static void UseThreadLocalClass()
{
var demo = new ThreadLocalComputer();
var thread_a = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_a" };
var thread_b = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_b" };
thread_a.Start();
thread_b.Start();
thread_a.Join();
thread_b.Join();
//调用线程:[主线程|内核线程] 共享字段的值。不加处理的话,可能小于多线程调用次数之和。
Console.WriteLine("调用线程的共享变量值 = " + Computer.TotalCount);
}
}
/// <summary>
/// 不使用本地存储
/// </summary>
/// <remarks>
/// 由于 ++ -- += -= 等对共享变量的操作不是原子性的,多线程下是不安全的。
/// </remarks>
public class Computer
{
/// <summary>
/// 总计算次数
/// </summary>
//[ThreadStatic]
public static int TotalCount = 0;
/// <summary>
/// 循环次数
/// </summary>
public readonly int LoopNumber = 1000;
/// <summary>
/// 累加计数
/// </summary>
public void SumCount()
{
for (int i = 1; i <= LoopNumber; i++)
{
//因为 += 是和等于的两步操作,所以不是线程安全的。
TotalCount += 1;
//如果使用原子操作,则是线程安全的
//Interlocked.Increment(ref TotalCount);
//加休眠是为了让并发效果明显,不加休眠可以增加循环次数
Thread.Sleep(1);
}
Console.WriteLine($"线程[{Thread.CurrentThread.ManagedThreadId.ToString("000")}]执行后,共享变量 {nameof(TotalCount)} = {TotalCount}");
}
}
/// <summary>
/// 使用本地存储ThreadStatic 特性
/// </summary>
/// <remarks>
/// 特点:只能用于静态变量上,不能用于实例上(语法不报错,实际不起作用)
/// </remarks>
public class ThreadStaticComputer
{
/// <summary>
/// 总计算次数
/// </summary>
[ThreadStatic]
public static int TotalCount = 0;
/// <summary>
/// 循环次数
/// </summary>
public readonly int LoopNumber = 100;
/// <summary>
/// 累加计数
/// </summary>
public void SumCount()
{
for (int i = 1; i <= LoopNumber; i++)
{
TotalCount += 1;
Thread.Sleep(0);
}
Console.WriteLine($"线程[{Thread.CurrentThread.ManagedThreadId.ToString("000")}]执行后,共享变量 {nameof(TotalCount)} = {TotalCount}");
}
}
/// <summary>
/// 使用本地存储:数据槽
/// </summary>
/// <remarks>
/// 特点:可以用于静态也可用于实例
/// </remarks>
public class DataSlotComputer
{
/// <summary>
/// 总计算次数
/// </summary>
public static int TotalCount = 0;
/// <summary>
/// 循环次数
/// </summary>
public readonly int LoopNumber = 100;
/// <summary>
/// 数据槽
/// </summary>
public LocalDataStoreSlot storeSlot = Thread.AllocateDataSlot();
/// <summary>
/// 累加计数值
/// </summary>
public void SumCount()
{
for (int i = 1; i <= LoopNumber; i++)
{
Thread.SetData(storeSlot, i);
//加休眠是为了让并发效果明显,不加休眠可以增加循环次数
Thread.Sleep(0);
}
//严格讲,这里也不是线程安全的。少量线程不安全的概率很小.可以使用原子操作实现。
TotalCount += (int)Thread.GetData(storeSlot);
//保证线程安全的话,可用原子操作
//Interlocked.Add(ref TotalCount, (int)Thread.GetData(storeSlot));
Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId.ToString("000")}执行后,共享变量{nameof(TotalCount)} = {TotalCount}");
}
}
/// <summary>
/// 使用本地存储ThreadLocal泛型类
/// </summary>
/// <remarks>
/// 特点1、对静态和实例字段都提供了线程本地存储支持并允许指定默认值
/// 2、ThreadLocal的值是延迟计算的每线程第一次调用时计算实际的值
/// </remarks>
public class ThreadLocalComputer
{
/// <summary>
/// 总计算次数
/// </summary>
public static int TotalCount = 0;
/// <summary>
/// 循环次数
/// </summary>
public readonly int LoopNumber = 100;
/// <summary>
/// 线程本地存储数据
/// </summary>
public static ThreadLocal<int> threadTotalCount = new ThreadLocal<int>();
/// <summary>
/// 累加计数值
/// </summary>
public void SumCount()
{
for (int i = 1; i <= LoopNumber; i++)
{
threadTotalCount.Value += 1;
//加休眠是为了让并发效果明显,不加休眠可以增加循环次数
Thread.Sleep(0);
}
TotalCount += threadTotalCount.Value;
//保证线程安全的话,可用原子操作
//Interlocked.Add(ref TotalCount, threadTotalCount.Value);
Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId.ToString("000")}执行后,共享变量{nameof(TotalCount)} = {TotalCount}");
}
}
}