4
4
5
5
namespace dotnetCampus . Threading
6
6
{
7
+ /// <summary>
8
+ /// 只执行一次的等待
9
+ /// </summary>
10
+ /// <typeparam name="TResult"></typeparam>
7
11
public class ExecuteOnceAwaiter < TResult >
8
12
{
13
+ /// <summary>
14
+ /// 创建只执行一次的等待,调用 <see cref="ExecuteAsync"/> 时,无论调用多少次,只会执行 <paramref name="asyncAction"/> 一次
15
+ /// <para></para>
16
+ /// 因为此类使用了锁,因此需要调用方处理 <paramref name="asyncAction"/> 自身线程安全问题
17
+ /// </summary>
18
+ /// <param name="asyncAction">执行的具体逻辑,需要调用方处理自身线程安全问题</param>
9
19
public ExecuteOnceAwaiter ( Func < Task < TResult > > asyncAction )
10
20
{
11
21
_asyncAction = asyncAction ;
12
22
}
13
23
24
+ /// <summary>
25
+ /// 执行传入的具体逻辑,无论多少线程多少次调用,传入的具体逻辑只会执行一次
26
+ /// </summary>
27
+ /// <returns></returns>
14
28
public Task < TResult > ExecuteAsync ( )
15
29
{
16
- if ( _executionResult != null )
30
+ lock ( _locker )
17
31
{
32
+ if ( _executionResult != null )
33
+ {
34
+ return _executionResult ;
35
+ }
36
+
37
+ _executionResult = _asyncAction ( ) ;
18
38
return _executionResult ;
19
39
}
20
-
21
- Lock ( ( ) => _executionResult = _asyncAction ( ) ) ;
22
-
23
- return _executionResult ;
24
40
}
25
41
42
+ /// <summary>
43
+ /// 在传入的具体逻辑执行完成之后,设置允许重新执行。如果此具体逻辑还在执行中,那么此方法调用无效
44
+ /// </summary>
26
45
public void ResetWhileCompleted ( )
27
46
{
28
- if ( IsCompleted )
47
+ lock ( _locker )
29
48
{
30
- Lock ( ( ) => _executionResult = null ) ;
49
+ if ( _executionResult ? . IsCompleted is true )
50
+ {
51
+ _executionResult = null ;
52
+ }
31
53
}
32
54
}
33
55
56
+ private readonly object _locker = new object ( ) ;
57
+
34
58
private readonly Func < Task < TResult > > _asyncAction ;
35
59
private Task < TResult > _executionResult ;
36
- private SpinLock _spinLock = new SpinLock ( true ) ;
37
-
38
- private bool IsRunning => _executionResult ? . IsCompleted is false ;
39
-
40
- private bool IsCompleted => _executionResult ? . IsCompleted is true ;
41
-
42
- private void Lock ( Action action )
43
- {
44
- var lockTaken = false ;
45
- try
46
- {
47
- _spinLock . Enter ( ref lockTaken ) ;
48
- action ( ) ;
49
- }
50
- finally
51
- {
52
- // 参数错误或锁递归时才会发生异常,所以此处几乎能肯定 lockTaken 为 true。
53
- if ( lockTaken ) _spinLock . Exit ( ) ;
54
- }
55
- }
56
60
}
57
61
}
0 commit comments