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#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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}");
}
}
}