Skip to content

Commit 53df3cb

Browse files
committed
main
1 parent 837bada commit 53df3cb

File tree

9 files changed

+101
-222
lines changed

9 files changed

+101
-222
lines changed

docs/document/Modern CSharp/docs/Parallel Programming/Synchronization/Problem of Atomicity.md renamed to docs/document/Modern CSharp/docs/Parallel Programming/Synchronization/1.Problem of Atomicity.md

File renamed without changes.

docs/document/Modern CSharp/docs/Parallel Programming/Synchronization/Monitor & lock Keyword.md renamed to docs/document/Modern CSharp/docs/Parallel Programming/Synchronization/2.Monitor & lock Keyword.md

File renamed without changes.

docs/document/Modern CSharp/docs/Parallel Programming/Synchronization/Mutex.md renamed to docs/document/Modern CSharp/docs/Parallel Programming/Synchronization/3.Mutex.md

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -35,46 +35,35 @@ BankAccount account = new();
3535
3636
Mutex mutex = new(); // use one mutex for only one object
3737
38-
var deposits = Enumerable.Range(1, 1000).Select(_ => Task.Run(() =>
39-
{
38+
var deposits = Enumerable.Range(1, 1000).Select(_ => Task.Run(() => {
4039
bool locked = mutex.WaitOne();
41-
try
42-
{
40+
try {
4341
if (locked) account.Deposit(100);
44-
}
45-
finally
46-
{
42+
} finally {
4743
if (locked) mutex.ReleaseMutex();
4844
}
4945
}));
50-
var withdraws = Enumerable.Range(1, 1000).Select(_ => Task.Run(() =>
51-
{
46+
var withdraws = Enumerable.Range(1, 1000).Select(_ => Task.Run(() => {
5247
bool locked = mutex.WaitOne();
53-
try
54-
{
48+
try {
5549
if (locked) account.Withdraw(100);
56-
}
57-
finally
58-
{
50+
} finally {
5951
if (locked) mutex.ReleaseMutex();
6052
}
6153
}));
6254
```
6355

6456
```cs[Like Monitor]
65-
public class BankAccount
66-
{
57+
public class BankAccount {
6758
public int Balance { get; private set; }
6859
// this is not recommeneded // [!code warning]
6960
private readonly Mutex _mutex = new(); // [!code ++]
70-
public void Deposit(int amount)
71-
{
61+
public void Deposit(int amount) {
7262
_mutex.WaitOne(); // [!code ++]
7363
Balance += amount;
7464
_mutex.ReleaseMutex(); // [!code ++]
7565
}
76-
public void Withdraw(int amount)
77-
{
66+
public void Withdraw(int amount) {
7867
_mutex.WaitOne(); // [!code ++]
7968
Balance -= amount;
8069
_mutex.ReleaseMutex(); // [!code ++]
@@ -105,44 +94,31 @@ BankAccount to = new();
10594
Mutex mutexFrom = new(); // [!code highlight]
10695
Mutex mutexTo = new(); // [!code highlight]
10796
108-
var deposits = Enumerable.Range(1, 1000).Select(_ => Task.Run(() =>
109-
{
97+
var deposits = Enumerable.Range(1, 1000).Select(_ => Task.Run(() => {
11098
bool locked = mutexFrom.WaitOne();
111-
try
112-
{
99+
try {
113100
if (locked) from.Deposit(100);
114-
}
115-
finally
116-
{
101+
} finally {
117102
if (locked) mutexFrom.ReleaseMutex();
118103
}
119104
}));
120105

121-
var withdraws = Enumerable.Range(1, 1000).Select(_ => Task.Run(() =>
122-
{
106+
var withdraws = Enumerable.Range(1, 1000).Select(_ => Task.Run(() => {
123107
bool locked = mutexTo.WaitOne();
124-
try
125-
{
108+
try {
126109
if (locked) to.Withdraw(100);
127-
}
128-
finally
129-
{
110+
} finally {
130111
if (locked) mutexTo.ReleaseMutex();
131112
}
132113
}));
133114

134-
Task transfer = Task.Run(() =>
135-
{
115+
Task transfer = Task.Run(() => {
136116
Thread.Sleep(100); // just make sure transfer happens after Deposit and Withdraw
137117
bool locked = Mutex.WaitAll([mutexFrom, mutexTo]); // same as WaitHandle.WaitAll // [!code highlight]
138-
try
139-
{
118+
try {
140119
if (locked) BankAccount.Transfer(from, to, from.Balance);
141-
}
142-
finally
143-
{
144-
if (locked)
145-
{
120+
} finally {
121+
if (locked) {
146122
// release all of them
147123
mutexFrom.ReleaseMutex(); // [!code highlight]
148124
mutexTo.ReleaseMutex(); // [!code highlight]
@@ -161,7 +137,7 @@ Console.WriteLine(to.Balance); // 0
161137
Global Mutex is created by Mutex constructor with a specified name.
162138
It's registered by it's name across the operating system.
163139

164-
- Use `Mutex.OpenExisting` to open a registered glbal mutex by its name.
140+
- Use `Mutex.OpenExisting` to open a registered global mutex by its name.
165141
- This always returns a mutex represents the registered one.(the reference might be different)
166142
```cs
167143
_ = Mutex.OpenExisting("Global\\...");
@@ -177,16 +153,12 @@ internal class Program
177153

178154
const string MutexId = "Global\\149b89b4-3bc9-4df5-9064-5d28b4ae8ca4"; // must start with Global\ // [!code highlight]
179155
static Mutex? mutex = null;
180-
private static void Main(string[] args)
181-
{
182-
try
183-
{
156+
private static void Main(string[] args) {
157+
try {
184158
// might throw here when mutex not registered with the name
185159
_ = Mutex.OpenExisting(MutexId);
186160
Console.WriteLine($"{MutexId} is running, cannot start another instance.");
187-
}
188-
catch (WaitHandleCannotBeOpenedException)
189-
{
161+
} catch (WaitHandleCannotBeOpenedException) {
190162
mutex = new Mutex(false, MutexId); // register the mutex, `initiallyOwned` doesn't matter here
191163
Console.WriteLine("A unique instance is started");
192164
}
@@ -198,7 +170,7 @@ internal class Program
198170
```
199171

200172
> [!NOTE]
201-
> `Local\` is no required when creating a local mutex
173+
> `Local\` is not required when creating a local mutex
202174
203175
## Abandoned Mutex
204176

docs/document/Modern CSharp/docs/Parallel Programming/Synchronization/Reader & Writer Lock.md renamed to docs/document/Modern CSharp/docs/Parallel Programming/Synchronization/4.Reader & Writer Lock.md

File renamed without changes.

docs/document/Modern CSharp/docs/Parallel Programming/Task/Task Creation.md renamed to docs/document/Modern CSharp/docs/Parallel Programming/Task/1.Task Creation.md

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ To start a job there's multiple approaches to do the same:
2727
_ = Task.Factory.StartNew(() => Console.WriteLine("hello"));
2828
_ = Task.Run(() => Console.WriteLine("hello"));
2929

30-
var fooAsync = async () =>
31-
{
30+
var fooAsync = async () => {
3231
await Task.Run(() => Console.WriteLine("foo"));
3332
};
3433

@@ -55,8 +54,7 @@ Both `TaskFactory` and `Task` supports an overload to accept **single argument**
5554
Since only single value is supported, you may need an abstraction when to pass multiple values
5655

5756
```cs
58-
_ = Task.Factory.StartNew((object foo) => // [!code highlight]
59-
{
57+
_ = Task.Factory.StartNew((object foo) => {
6058
Console.WriteLine(foo.GetType());
6159
}, 123);
6260

@@ -76,15 +74,13 @@ task.Start();
7674
Each `async` delegate is like a factory for it's dedicated action only.
7775

7876
```cs
79-
Func<Task> foo = async () =>
80-
{
77+
Func<Task> foo = async () => {
8178
await Task.Delay(100);
8279
};
8380

8481
await foo();
8582

86-
Func<int, Task<int>> bar = async (int number) =>
87-
{
83+
Func<int, Task<int>> bar = async (int number) => {
8884
await Task.Delay(1000);
8985
return number;
9086
};
@@ -95,8 +91,7 @@ bar(123).Wait();
9591
And it can be super useful when creating a batch of tasks using LINQ:
9692

9793
```cs
98-
_ = await Task.WhenAll(Enumerable.Range(1, 10).Select(async x =>
99-
{
94+
_ = await Task.WhenAll(Enumerable.Range(1, 10).Select(async x => {
10095
await Task.Delay(100);
10196
return x;
10297
}));
@@ -110,22 +105,19 @@ That is because, `async` delegate is a factory for dedicated task, so the result
110105

111106
```cs
112107
// note: it's a wrapped task
113-
Task<Task<int>> t = Task.Factory.StartNew(async () =>
114-
{
108+
Task<Task<int>> t = Task.Factory.StartNew(async () => {
115109
await Task.Delay(1000);
116110
return 42;
117111
});
118112

119113
// use this instead!!
120-
Task<int> t2 = Task.Factory.StartNew(async () =>
121-
{
114+
Task<int> t2 = Task.Factory.StartNew(async () => {
122115
await Task.Delay(1000);
123116
return 42;
124117
}).Unwrap();
125118

126119
// functionally you can use await to unwrap but it's definitely not recommended
127-
Task<int> t2 = await Task.Factory.StartNew(async () =>
128-
{
120+
Task<int> t2 = await Task.Factory.StartNew(async () => {
129121
await Task.Delay(1000);
130122
return 42;
131123
});
@@ -136,8 +128,7 @@ Task<int> t2 = await Task.Factory.StartNew(async () =>
136128
> `Task.Run` has a implicit auto-unwrap for some of its overloads, you may prefer this over `TaskFactory.StartNew` to start a simple task.
137129
>```cs
138130
>// The type is unwraped
139-
>Task<int> t = Task.Run(async () =>
140-
>{
131+
>Task<int> t = Task.Run(async () => {
141132
> await Task.Delay(1000);
142133
> return 42;
143134
>});
@@ -247,10 +238,8 @@ _ = Task.Factory.StartNew(
247238
- `Thread.Sleep`: pauses the thread and allows the scheduler to run another thread while sleeping, for the efficiency.
248239
- `SpinWait.SpinUntil`: pauses the thread until a condition fits. The scheduler are not allowed to run another thread using current resource of this thread.
249240
```cs
250-
Task task = new(() =>
251-
{
252-
SpinWait.SpinUntil(() =>
253-
{
241+
Task task = new(() => {
242+
SpinWait.SpinUntil(() => {
254243
return true;
255244
}, 1000);
256245
});

docs/document/Modern CSharp/docs/Parallel Programming/Task/Wait for Task.md renamed to docs/document/Modern CSharp/docs/Parallel Programming/Task/2.Wait for Task.md

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ Waiting a task means the execution of code is synchronous but there's a essentia
1616
- `await` operator waits the task without blocking the calling thread.
1717
```cs
1818
int foo = await Foo(); // does not block the main thread but still synchronous
19-
static async Task<int> Foo
20-
{
19+
static async Task<int> Foo {
2120
await Task.Delay(500);
2221
return 123;
2322
}
@@ -42,8 +41,7 @@ await task;
4241
Starting a simple task manually is quiet trivial so one should prefer `Task.Run` or `Task.Factory.StartNew`
4342

4443
```cs
45-
await Task.Factory.StartNew((object? foo) =>
46-
{
44+
await Task.Factory.StartNew((object? foo) => {
4745
Console.WriteLine(((dynamic)foo).Foo);
4846
}, new { Foo = 345 });
4947

@@ -59,8 +57,7 @@ await Task.Run(() => { Console.WriteLine("hello"); });
5957
> `WhenAll` and `WhenAny` do not start tasks for you, make sure they're started before waiting.
6058
6159
```cs
62-
IEnumerable<Task<int>> tasks = Enumerable.Range(1, 10).Select(async x =>
63-
{
60+
IEnumerable<Task<int>> tasks = Enumerable.Range(1, 10).Select(async x => {
6461
await Task.Delay(x * 100);
6562
return x;
6663
});
@@ -77,32 +74,23 @@ Console.WriteLine(first.Result); // should be 1
7774
```cs
7875
using CancellationTokenSource cts = new();
7976
var token = cts.Token;
80-
Task task = new Task(() =>
81-
{
77+
Task task = new Task(() => {
8278
int i = Random.Shared.Next(1, 5); // random countdown // [!code highlight]
83-
while (i-- > 0)
84-
{
79+
while (i-- > 0) {
8580
token.ThrowIfCancellationRequested();
8681
Console.WriteLine("operation...");
8782
Thread.Sleep(1000);
8883
}
8984
}, token);
9085

91-
try
92-
{
86+
try {
9387
task.Start(); // [!code highlight]
94-
if (task == await Task.WhenAny(task, Task.Delay(3000))) // to race with the delay // [!code highlight]
95-
{
88+
if (task == await Task.WhenAny(task, Task.Delay(3000))) { // to race with the delay // [!code highlight]
9689
Console.WriteLine("Task succeeded");
97-
}
98-
else
99-
{
90+
} else {
10091
cts.Cancel();
10192
Console.WriteLine("Task canceled for timeout");
10293
}
103-
}
104-
catch (OperationCanceledException)
105-
{
106-
}
94+
} catch (OperationCanceledException) { }
10795
```
10896

0 commit comments

Comments
 (0)