|
|
@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
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}");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|