272 lines
9.8 KiB
Markdown
272 lines
9.8 KiB
Markdown
|
|
#unity/日常积累
|
|||
|
|
|
|||
|
|
## 定义
|
|||
|
|
|
|||
|
|
命名空间:
|
|||
|
|
|
|||
|
|
[System.Threading](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading?view=net-8.0)
|
|||
|
|
|
|||
|
|
程序集:
|
|||
|
|
|
|||
|
|
System.Threading.dll
|
|||
|
|
|
|||
|
|
以原子操作的形式递减指定变量的值并存储结果。
|
|||
|
|
|
|||
|
|
[](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.interlocked.decrement?view=net-8.0#--)
|
|||
|
|
|
|||
|
|
## 重载
|
|||
|
|
|
|||
|
|
展开表
|
|||
|
|
|
|||
|
|
[Decrement(Int32)](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.interlocked.decrement?view=net-8.0#system-threading-interlocked-decrement(system-int32@))
|
|||
|
|
|
|||
|
|
以原子操作的形式递减指定变量的值并存储结果。
|
|||
|
|
|
|||
|
|
[Decrement(Int64)](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.interlocked.decrement?view=net-8.0#system-threading-interlocked-decrement(system-int64@))
|
|||
|
|
|
|||
|
|
以原子操作的形式递减指定变量的值并存储结果。
|
|||
|
|
|
|||
|
|
[Decrement(UInt32)](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.interlocked.decrement?view=net-8.0#system-threading-interlocked-decrement(system-uint32@))
|
|||
|
|
|
|||
|
|
以原子操作的形式递减指定变量的值并存储结果。
|
|||
|
|
|
|||
|
|
[Decrement(UInt64)](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.interlocked.decrement?view=net-8.0#system-threading-interlocked-decrement(system-uint64@))
|
|||
|
|
|
|||
|
|
以原子操作的形式递减指定变量的值并存储结果。
|
|||
|
|
|
|||
|
|
[](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.interlocked.decrement?view=net-8.0#system-threading-interlocked-decrement(system-int32@))
|
|||
|
|
|
|||
|
|
## Decrement(Int32)
|
|||
|
|
|
|||
|
|
以原子操作的形式递减指定变量的值并存储结果。
|
|||
|
|
|
|||
|
|
``` cs
|
|||
|
|
public static int Decrement (ref int location);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 参数
|
|||
|
|
|
|||
|
|
location
|
|||
|
|
|
|||
|
|
[Int32](https://learn.microsoft.com/zh-cn/dotnet/api/system.int32?view=net-8.0)
|
|||
|
|
|
|||
|
|
其值要递减的变量。
|
|||
|
|
|
|||
|
|
#### 返回
|
|||
|
|
|
|||
|
|
[Int32](https://learn.microsoft.com/zh-cn/dotnet/api/system.int32?view=net-8.0)
|
|||
|
|
|
|||
|
|
递减操作完成后紧接变量的值。
|
|||
|
|
|
|||
|
|
#### 例外
|
|||
|
|
|
|||
|
|
[ArgumentNullException](https://learn.microsoft.com/zh-cn/dotnet/api/system.argumentnullexception?view=net-8.0)
|
|||
|
|
|
|||
|
|
`location` 的地址是一个 `null` 指针。
|
|||
|
|
|
|||
|
|
[NullReferenceException](https://learn.microsoft.com/zh-cn/dotnet/api/system.nullreferenceexception?view=net-8.0)
|
|||
|
|
|
|||
|
|
`location` 的地址是一个 `null` 指针。
|
|||
|
|
|
|||
|
|
### 示例
|
|||
|
|
|
|||
|
|
以下示例确定需要多少个介于 0 到 1,000 的随机数才能生成具有中点值的 1,000 个随机数。 为了跟踪中点值的数量,变量 `midpointCount`设置为等于 1,000,并在随机数生成器每次返回中点值时递减。 由于三个线程生成随机数, [Decrement(Int32)](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.interlocked.decrement?view=net-8.0#system-threading-interlocked-decrement(system-int32@)) 因此调用 方法以确保多个线程不会同时更新 `midpointCount` 。 请注意,锁还用于保护随机数生成器,并使用 对象来确保`Main`方法不会在三个[CountdownEvent](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.countdownevent?view=net-8.0)线程之前完成执行。
|
|||
|
|
|
|||
|
|
``` cs
|
|||
|
|
using System;
|
|||
|
|
using System.Threading;
|
|||
|
|
|
|||
|
|
public class Example
|
|||
|
|
{
|
|||
|
|
const int LOWERBOUND = 0;
|
|||
|
|
const int UPPERBOUND = 1001;
|
|||
|
|
|
|||
|
|
static Object lockObj = new Object();
|
|||
|
|
static Random rnd = new Random();
|
|||
|
|
static CountdownEvent cte;
|
|||
|
|
|
|||
|
|
static int totalCount = 0;
|
|||
|
|
static int totalMidpoint = 0;
|
|||
|
|
static int midpointCount = 10000;
|
|||
|
|
|
|||
|
|
public static void Main()
|
|||
|
|
{
|
|||
|
|
cte = new CountdownEvent(1);
|
|||
|
|
// Start three threads.
|
|||
|
|
for (int ctr = 0; ctr <= 2; ctr++) {
|
|||
|
|
cte.AddCount();
|
|||
|
|
Thread th = new Thread(GenerateNumbers);
|
|||
|
|
th.Name = "Thread" + ctr.ToString();
|
|||
|
|
th.Start();
|
|||
|
|
}
|
|||
|
|
cte.Signal();
|
|||
|
|
cte.Wait();
|
|||
|
|
Console.WriteLine();
|
|||
|
|
Console.WriteLine("Total midpoint values: {0,10:N0} ({1:P3})",
|
|||
|
|
totalMidpoint, totalMidpoint/((double)totalCount));
|
|||
|
|
Console.WriteLine("Total number of values: {0,10:N0}",
|
|||
|
|
totalCount);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static void GenerateNumbers()
|
|||
|
|
{
|
|||
|
|
int midpoint = (UPPERBOUND - LOWERBOUND) / 2;
|
|||
|
|
int value = 0;
|
|||
|
|
int total = 0;
|
|||
|
|
int midpt = 0;
|
|||
|
|
|
|||
|
|
do {
|
|||
|
|
lock (lockObj) {
|
|||
|
|
value = rnd.Next(LOWERBOUND, UPPERBOUND);
|
|||
|
|
}
|
|||
|
|
if (value == midpoint) {
|
|||
|
|
Interlocked.Decrement(ref midpointCount);
|
|||
|
|
midpt++;
|
|||
|
|
}
|
|||
|
|
total++;
|
|||
|
|
} while (Volatile.Read(ref midpointCount) > 0);
|
|||
|
|
|
|||
|
|
Interlocked.Add(ref totalCount, total);
|
|||
|
|
Interlocked.Add(ref totalMidpoint, midpt);
|
|||
|
|
|
|||
|
|
string s = String.Format("Thread {0}:\n", Thread.CurrentThread.Name) +
|
|||
|
|
String.Format(" Random Numbers: {0:N0}\n", total) +
|
|||
|
|
String.Format(" Midpoint values: {0:N0} ({1:P3})", midpt,
|
|||
|
|
((double) midpt)/total);
|
|||
|
|
Console.WriteLine(s);
|
|||
|
|
cte.Signal();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// The example displays output like the following:
|
|||
|
|
// Thread Thread2:
|
|||
|
|
// Random Numbers: 3,204,021
|
|||
|
|
// Midpoint values: 3,156 (0.099 %)
|
|||
|
|
// Thread Thread0:
|
|||
|
|
// Random Numbers: 4,073,592
|
|||
|
|
// Midpoint values: 4,015 (0.099 %)
|
|||
|
|
// Thread Thread1:
|
|||
|
|
// Random Numbers: 2,828,192
|
|||
|
|
// Midpoint values: 2,829 (0.100 %)
|
|||
|
|
//
|
|||
|
|
// Total midpoint values: 10,000 (0.099 %)
|
|||
|
|
// Total number of values: 10,105,805
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
下面的示例与上一个示例类似,只不过它使用 [Task](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.tasks.task?view=net-8.0) 类而不是线程过程来生成 50,000 个随机中点整数。 在此示例中,lambda 表达式替换了 `GenerateNumbers` 线程过程,对 方法的调用 [Task.WaitAll](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.tasks.task.waitall?view=net-8.0) 消除了对 [CountdownEvent](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.countdownevent?view=net-8.0) 对象的需要。
|
|||
|
|
|
|||
|
|
``` cs
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Threading;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
|
|||
|
|
public class Example
|
|||
|
|
{
|
|||
|
|
const int LOWERBOUND = 0;
|
|||
|
|
const int UPPERBOUND = 1001;
|
|||
|
|
|
|||
|
|
static Object lockObj = new Object();
|
|||
|
|
static Random rnd = new Random();
|
|||
|
|
|
|||
|
|
static int totalCount = 0;
|
|||
|
|
static int totalMidpoint = 0;
|
|||
|
|
static int midpointCount = 50000;
|
|||
|
|
|
|||
|
|
public static async Task Main()
|
|||
|
|
{
|
|||
|
|
List<Task> tasks = new List<Task>();
|
|||
|
|
|
|||
|
|
// Start three tasks.
|
|||
|
|
for (int ctr = 0; ctr <= 2; ctr++)
|
|||
|
|
tasks.Add(Task.Run( () => { int midpoint = (UPPERBOUND - LOWERBOUND) / 2;
|
|||
|
|
int value = 0;
|
|||
|
|
int total = 0;
|
|||
|
|
int midpt = 0;
|
|||
|
|
|
|||
|
|
do {
|
|||
|
|
lock (lockObj) {
|
|||
|
|
value = rnd.Next(LOWERBOUND, UPPERBOUND);
|
|||
|
|
}
|
|||
|
|
if (value == midpoint) {
|
|||
|
|
Interlocked.Decrement(ref midpointCount);
|
|||
|
|
midpt++;
|
|||
|
|
}
|
|||
|
|
total++;
|
|||
|
|
} while (Volatile.Read(ref midpointCount) > 0);
|
|||
|
|
|
|||
|
|
Interlocked.Add(ref totalCount, total);
|
|||
|
|
Interlocked.Add(ref totalMidpoint, midpt);
|
|||
|
|
|
|||
|
|
string s = String.Format("Task {0}:\n", Task.CurrentId) +
|
|||
|
|
String.Format(" Random Numbers: {0:N0}\n", total) +
|
|||
|
|
String.Format(" Midpoint values: {0:N0} ({1:P3})", midpt,
|
|||
|
|
((double) midpt)/total);
|
|||
|
|
Console.WriteLine(s);
|
|||
|
|
} ));
|
|||
|
|
|
|||
|
|
await Task.WhenAll(tasks.ToArray());
|
|||
|
|
|
|||
|
|
Console.WriteLine();
|
|||
|
|
Console.WriteLine("Total midpoint values: {0,10:N0} ({1:P3})",
|
|||
|
|
totalMidpoint, totalMidpoint/((double)totalCount));
|
|||
|
|
Console.WriteLine("Total number of values: {0,10:N0}",
|
|||
|
|
totalCount);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// The example displays output like the following:
|
|||
|
|
// Task 1:
|
|||
|
|
// Random Numbers: 24,530,624
|
|||
|
|
// Midpoint values: 24,675 (0.101 %)
|
|||
|
|
// Task 2:
|
|||
|
|
// Random Numbers: 7,079,718
|
|||
|
|
// Midpoint values: 7,093 (0.100 %)
|
|||
|
|
// Task 3:
|
|||
|
|
// Random Numbers: 18,284,617
|
|||
|
|
// Midpoint values: 18,232 (0.100 %)
|
|||
|
|
//
|
|||
|
|
// Total midpoint values: 50,000 (0.100 %)
|
|||
|
|
// Total number of values: 49,894,959
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 注解
|
|||
|
|
|
|||
|
|
此方法通过包装处理溢出条件:如果 `location` = [Int32.MinValue](https://learn.microsoft.com/zh-cn/dotnet/api/system.int32.minvalue?view=net-8.0#system-int32-minvalue), `location` 则 - 1 = 。 [Int32.MaxValue](https://learn.microsoft.com/zh-cn/dotnet/api/system.int32.maxvalue?view=net-8.0#system-int32-maxvalue) 不会引发异常。
|
|||
|
|
|
|||
|
|
### 另请参阅
|
|||
|
|
|
|||
|
|
- [托管线程](https://learn.microsoft.com/zh-cn/dotnet/standard/threading/)
|
|||
|
|
- [同步基元概述](https://learn.microsoft.com/zh-cn/dotnet/standard/threading/overview-of-synchronization-primitives)
|
|||
|
|
|
|||
|
|
### 适用于
|
|||
|
|
|
|||
|
|
.NET 8 和其他版本
|
|||
|
|
|
|||
|
|
产品
|
|||
|
|
|
|||
|
|
版本
|
|||
|
|
|
|||
|
|
.NET
|
|||
|
|
|
|||
|
|
Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8
|
|||
|
|
|
|||
|
|
.NET Framework
|
|||
|
|
|
|||
|
|
1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
|
|||
|
|
|
|||
|
|
.NET Standard
|
|||
|
|
|
|||
|
|
1.0, 1.1, 1.2, 1.3, 1.4, 1.6, 2.0, 2.1
|
|||
|
|
|
|||
|
|
UWP
|
|||
|
|
|
|||
|
|
10.0
|
|||
|
|
|
|||
|
|
Xamarin.iOS
|
|||
|
|
|
|||
|
|
10.8
|
|||
|
|
|
|||
|
|
Xamarin.Mac
|
|||
|
|
|
|||
|
|
3.0
|
|||
|
|
|
|||
|
|
[](https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.interlocked.decrement?view=net-8.0#system-threading-interlocked-decrement(system-int64@))
|