|
|
|
@ -120,7 +120,7 @@
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"### Increment\n",
|
|
|
|
|
"### 原子递增 Interlocked.Increment()\n",
|
|
|
|
|
"Interlocked.Increment 函数执行的原子操作属于 “获取-添加”分类,执行后变量的值增加1,返回的值是增加后的值,即增加前的值加1"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
@ -178,6 +178,430 @@
|
|
|
|
|
"\n",
|
|
|
|
|
"//原子操作,多线程下多次执行结果相同"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"## 原子递减 Interlocked.Decrement()"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"属于 `获取-添加`分类,执行后变量的值减少1,返回值是减少后的值即原值减1"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
"metadata": {
|
|
|
|
|
"dotnet_interactive": {
|
|
|
|
|
"language": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"polyglot_notebook": {
|
|
|
|
|
"kernelName": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"vscode": {
|
|
|
|
|
"languageId": "polyglot-notebook"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"#region 原子递减\n",
|
|
|
|
|
"//原子递减\n",
|
|
|
|
|
"public class Counter4Decrement\n",
|
|
|
|
|
"{\n",
|
|
|
|
|
" //总次数\n",
|
|
|
|
|
" public static int TotalNumber = 0;\n",
|
|
|
|
|
" \n",
|
|
|
|
|
" //方法循环次数\n",
|
|
|
|
|
" public static readonly int LoopNumber = 10000;\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //执行\n",
|
|
|
|
|
" public static void Decrement()\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" for (int i = 1; i <= LoopNumber; i++)\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" //原子操作:循环递减,返回递减后的值\n",
|
|
|
|
|
" var decreValue = System.Threading.Interlocked.Decrement(ref TotalNumber);\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
" Console.WriteLine($\"线程[{Thread.CurrentThread.Name}] 执行了递减 {LoopNumber} 次,结束时 TotalNumber = {TotalNumber}\");\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
"}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"//使用域隔离和代码折叠\n",
|
|
|
|
|
"{\n",
|
|
|
|
|
" var threads = new List<Thread>()\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" new Thread(Counter4Decrement.Decrement){Name=\"thread_a\"},\n",
|
|
|
|
|
" new Thread(Counter4Decrement.Decrement){Name=\"thread_b\"}\n",
|
|
|
|
|
" };\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" threads.ForEach(t => t.Start());\n",
|
|
|
|
|
" threads.ForEach(t => t.Join());\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //主线程信息\n",
|
|
|
|
|
" Console.WriteLine($\"主(执行)线程[{Thread.CurrentThread.Name}] 结束时,TotalLoopNumber = {Counter4Decrement.TotalNumber}\");\n",
|
|
|
|
|
"}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"//原子操作:\n",
|
|
|
|
|
"//1、多线程下,每线程执行结束后共享变量可能不同\n",
|
|
|
|
|
"//2、所有线程结束, 主线程获取的变量值与最后完成的线程值相同\n",
|
|
|
|
|
"#endregion"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"## 原子增加指定数量(负数为减) Interlocked.Add()"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"Interlocked.Add 属于 `获取-添加`分类,执行后变量的值加等于第二个参数的值,返回值是增加后的值即原值加第二个参数值"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
"metadata": {
|
|
|
|
|
"dotnet_interactive": {
|
|
|
|
|
"language": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"polyglot_notebook": {
|
|
|
|
|
"kernelName": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"vscode": {
|
|
|
|
|
"languageId": "polyglot-notebook"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"//原子增加指定数量\n",
|
|
|
|
|
"public class Counter4Add\n",
|
|
|
|
|
"{\n",
|
|
|
|
|
" //共享变量\n",
|
|
|
|
|
" public static int ShareNumber = 0;\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //执行\n",
|
|
|
|
|
" public static void Add()\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" //随机休眠,打乱多线程执行顺序\n",
|
|
|
|
|
" Thread.Sleep(Random.Shared.Next(100,500));\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //原子操作:增加指定数量\n",
|
|
|
|
|
" var decreValue = System.Threading.Interlocked.Add(ref ShareNumber,2);\n",
|
|
|
|
|
" Console.WriteLine($\"线程[{Thread.CurrentThread.Name}] 递减2后, ShareNumber = {ShareNumber}\");\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
"}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"//使用域隔离和代码折叠\n",
|
|
|
|
|
"{\n",
|
|
|
|
|
" var threads = new List<Thread>()\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" new Thread(Counter4Add.Add){Name=\"thread_a\"},\n",
|
|
|
|
|
" new Thread(Counter4Add.Add){Name=\"thread_b\"}\n",
|
|
|
|
|
" };\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" threads.ForEach(t => t.Start());\n",
|
|
|
|
|
" threads.ForEach(t => t.Join());\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //主线程信息\n",
|
|
|
|
|
" Console.WriteLine($\"主[执行]线程获共享变量 ShareNumber 最终的值 = {Counter4Add.ShareNumber}\");\n",
|
|
|
|
|
"}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"//原子操作:\n",
|
|
|
|
|
"//1、两个线程同时执行会输出: 2 4 或 4 2\n",
|
|
|
|
|
"//2、全局变量最终的值为 4"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"## 原子替换 Interlocked.Exchange()"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"Interlocked.Exchange() 属于 `测试-设置` 分类, 将变量的值修改为第二个参数的值,返回修改前的值"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
"metadata": {
|
|
|
|
|
"dotnet_interactive": {
|
|
|
|
|
"language": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"polyglot_notebook": {
|
|
|
|
|
"kernelName": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"vscode": {
|
|
|
|
|
"languageId": "polyglot-notebook"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"//原子替换\n",
|
|
|
|
|
"public class Counter4Exchange\n",
|
|
|
|
|
"{\n",
|
|
|
|
|
" //共享变量\n",
|
|
|
|
|
" public static int ShareNumber = 0;\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //执行\n",
|
|
|
|
|
" public static void Exchange()\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" //随机休眠,打乱多线程执行顺序\n",
|
|
|
|
|
" Thread.Sleep(Random.Shared.Next(100,500));\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //原子操作:替换\n",
|
|
|
|
|
" var oldValue = System.Threading.Interlocked.Exchange(ref ShareNumber,1);\n",
|
|
|
|
|
" Console.WriteLine($\"线程[{Thread.CurrentThread.Name}] 替换前的值为 {oldValue}\");\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
"}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"//使用域隔离和代码折叠\n",
|
|
|
|
|
"{\n",
|
|
|
|
|
" var threads = new List<Thread>()\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" new Thread(Counter4Exchange.Exchange){Name=\"thread_a\"},\n",
|
|
|
|
|
" new Thread(Counter4Exchange.Exchange){Name=\"thread_b\"}\n",
|
|
|
|
|
" };\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" threads.ForEach(t => t.Start());\n",
|
|
|
|
|
" threads.ForEach(t => t.Join());\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //主线程信息\n",
|
|
|
|
|
" Console.WriteLine($\"主[执行]线程获共享变量 ShareNumber 最终的值 = {Counter4Exchange.ShareNumber}\");\n",
|
|
|
|
|
"}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"//原子替换:\n",
|
|
|
|
|
"//1、两个线程同时执行会输出: 0 1 或 1 0\n",
|
|
|
|
|
"//2、全局变量最终的值为 1"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"## 原子比较替换 Interlocked.CompareExchange()"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"Interlocked.CompareExchange() 属于 `比较-交换` 分类, 执行时如果变量的值等于第三个变量的值,则修改为第二个变量的值并返回修改前的值;否则直接返回现有值"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
"metadata": {
|
|
|
|
|
"dotnet_interactive": {
|
|
|
|
|
"language": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"polyglot_notebook": {
|
|
|
|
|
"kernelName": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"vscode": {
|
|
|
|
|
"languageId": "polyglot-notebook"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"//原子比较替换\n",
|
|
|
|
|
"public class Counter4CompareExchange\n",
|
|
|
|
|
"{\n",
|
|
|
|
|
" //共享变量\n",
|
|
|
|
|
" public static int ShareNumber = 0;\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //执行\n",
|
|
|
|
|
" public static void CompareExchange()\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" //随机休眠,打乱多线程执行顺序\n",
|
|
|
|
|
" Thread.Sleep(Random.Shared.Next(100,500));\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //原子操作:比较替换\n",
|
|
|
|
|
" int y;\n",
|
|
|
|
|
" while(true)\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" y = ShareNumber;\n",
|
|
|
|
|
" int oldShareValue = System.Threading.Interlocked.CompareExchange(ref ShareNumber,y+1,y);\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" if(oldShareValue == y)\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" break;\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Console.WriteLine($\"线程[{Thread.CurrentThread.Name}] 替换前的值为 {y+1}\");\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
"}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"//使用域隔离和代码折叠\n",
|
|
|
|
|
"{\n",
|
|
|
|
|
" var threads = new List<Thread>()\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" new Thread(Counter4CompareExchange.CompareExchange){Name=\"thread_a\"},\n",
|
|
|
|
|
" new Thread(Counter4CompareExchange.CompareExchange){Name=\"thread_b\"}\n",
|
|
|
|
|
" };\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" threads.ForEach(t => t.Start());\n",
|
|
|
|
|
" threads.ForEach(t => t.Join());\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //主线程信息\n",
|
|
|
|
|
" Console.WriteLine($\"主[执行]线程获共享变量 ShareNumber 最终的值 = {Counter4CompareExchange.ShareNumber}\");\n",
|
|
|
|
|
"}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"//原子替换:\n",
|
|
|
|
|
"//1、两个线程同时执行会输出: 1 2 或 2 1\n",
|
|
|
|
|
"//2、全局变量最终的值为 2"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"## 原子读取 Interlocked.Read()"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"从内存读取值通常都是原子的,除非32位平台读取64位数据,比如32位平台上读取 long 型数值。因为32位平台读取64位数据是分高位和低位两次读取操作的,所以不是原子操作。原子读取一般会与其它原子操作配合使用。"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
"metadata": {
|
|
|
|
|
"dotnet_interactive": {
|
|
|
|
|
"language": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"polyglot_notebook": {
|
|
|
|
|
"kernelName": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"vscode": {
|
|
|
|
|
"languageId": "polyglot-notebook"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"//原子读取\n",
|
|
|
|
|
"public class Counter4Read\n",
|
|
|
|
|
"{\n",
|
|
|
|
|
" //共享变量,64位数据\n",
|
|
|
|
|
" public static long ShareNumber = 0;\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //循环次数\n",
|
|
|
|
|
" public readonly static int LoopNumber = 10000;\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //一个线程循环替换数据\n",
|
|
|
|
|
" public static void Exchange()\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" for(int i=0; i< LoopNumber; i++)\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" System.Threading.Interlocked.Exchange(ref ShareNumber,0x7aaabbbbccccdddd);\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
" \n",
|
|
|
|
|
" //一个线程循环读取\n",
|
|
|
|
|
" //无论多少次读取的都是 0 或者 0x7aaabbbbccccdddd\n",
|
|
|
|
|
" //不可能是 0x7aaabbbb00000000 或者 ccccdddd\n",
|
|
|
|
|
" public static void Read()\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" for(int i=0; i< LoopNumber; i++)\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" long y = System.Threading.Interlocked.Read(ref ShareNumber);\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //此条件应该永远不成立\n",
|
|
|
|
|
" if(y==0x7aaabbbb00000000 || y==0x00000000ccccdddd)\n",
|
|
|
|
|
" { \n",
|
|
|
|
|
" Console.WriteLine($\"线程[{System.Threading.Thread.CurrentThread.Name}], 读取到非原子值{y}\");\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
" }\n",
|
|
|
|
|
"}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"//使用域隔离和代码折叠\n",
|
|
|
|
|
"{\n",
|
|
|
|
|
" var threads = new List<Thread>()\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" new Thread(Counter4Read.Exchange){Name=\"thread_a\"},\n",
|
|
|
|
|
" new Thread(Counter4Read.Read){Name=\"thread_b\"}\n",
|
|
|
|
|
" };\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" threads.ForEach(t => t.Start());\n",
|
|
|
|
|
" threads.ForEach(t => t.Join());\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" //主线程信息\n",
|
|
|
|
|
" Console.WriteLine($\"主[执行]线程获共享变量 ShareNumber 最终的值 = {Counter4Read.ShareNumber}\");\n",
|
|
|
|
|
"}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"//原子读取:\n",
|
|
|
|
|
"//1、无论多少次读取的都是 0 或者 0x7aaabbbbccccdddd 不可能是 0x7aaabbbb00000000 或者 ccccdddd\n",
|
|
|
|
|
"//2、全局变量最终的值为 0x7aaabbbbccccdddd 即是 8839083633937276381 或者极概率是 0"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"## 内存屏障 Interlocked.MemoryBarrier()"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {},
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"System.Threading.Interlocked 还提供了一些其它方法,比如内存屏障相关的 MemoryBarrier() 和 MemoryBarrierProcessWide() 和 新的 And() Or()方法等。"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
"metadata": {
|
|
|
|
|
"dotnet_interactive": {
|
|
|
|
|
"language": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"polyglot_notebook": {
|
|
|
|
|
"kernelName": "csharp"
|
|
|
|
|
},
|
|
|
|
|
"vscode": {
|
|
|
|
|
"languageId": "polyglot-notebook"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"/*\n",
|
|
|
|
|
"System.Threading.Interlocked.MemoryBarrier();\n",
|
|
|
|
|
"System.Threading.Interlocked.MemoryBarrierProcessWide();\n",
|
|
|
|
|
"System.Threading.Interlocked.And();\n",
|
|
|
|
|
"System.Threading.Interlocked.Or();\n",
|
|
|
|
|
"*/"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"metadata": {
|
|
|
|
|