多线程嘴巴上说的控制方式有很多,比如操作系统学的解决消费者生产者的信号量等等等
,但是实际使用的时候却不知道采用什么,比如我自己,就会使用全局变量来模拟线程控制
先分享博客的写作背景的题目:
leecode1114按序打印
lecode1115交替打印
按序打印采用了三种种解决方式,都是目前我学习到的一些方式
1:使用ManualResetEvent
先交代源码以及题目背景
using System.Threading;
public class Foo {
ManualResetEvent second = new ManualResetEvent(false);//初始值为false
ManualResetEvent third = new ManualResetEvent(false);
public Foo() {
}
public void First(Action printFirst) {
// printFirst() outputs "first". Do not change or remove this line.
printFirst();
second.Set();
}
public void Second(Action printSecond) {
second.WaitOne();
// printSecond() outputs "second". Do not change or remove this line.
printSecond();
third.Set();
}
public void Third(Action printThird) {
third.WaitOne();
// printThird() outputs "third". Do not change or remove this line.
printThird();
}
}
现在介绍一下ManualResetEvent的使用:
ManualResetEvent 主要有几个个重要使用方式:
参考博文
创建:就是普通类的创建
//true-初始状态为发出信号;false-初始状态为未发出信号,一般设置为false,手动来发出信号
ManualResetEvent mre = new ManualResetEvent(false);
ManualResetEvent mre = new ManualResetEvent(true);
重置:
first.Reset();
阻塞:
second.WaitOne();
解除阻塞:
second.Set();
在这里要提一嘴你在解除阻塞之后想要再次阻塞,需要通过先重置再阻塞
一般可以直接阻塞之后执行玩目标之后直接写重置
first.WaitOne();
printFoo();
first.Reset();
下面是一个高级一点的实战
源代码:
using System.Threading;
public class FooBar {
ManualResetEvent second = new ManualResetEvent(false);
ManualResetEvent first = new ManualResetEvent(false);
private int n;
public FooBar(int n) {
this.n = n;
first.Set();
}
public void Foo(Action printFoo) {
for (int i = 0; i < n; i++) {
first.WaitOne();
printFoo();
first.Reset();
second.Set();
}
}
public void Bar(Action printBar) {
// second.WaitOne();
for (int i = 0; i < n; i++) {
// printBar() outputs "bar". Do not change or remove this line.
second.WaitOne();
printBar();
second.Reset();
first.Set();
}
}
}
下面介绍另外一个变量:AutoResetEvent
使用何上一个相似,不过再阻塞不需要先进行重置喔。
private AutoResetEvent b = new AutoResetEvent(false);
下面将贴出,使用bool(也可以使用例如int等)模拟信号量机制的源码了:
using System.Threading;
public class Foo {
bool sec=false;
bool thi=false;
public Foo() {
}
public void First(Action printFirst) {
// printFirst() outputs "first". Do not change or remove this line.
printFirst();
sec= true;
//second.Set();
}
public void Second(Action printSecond) {
//second.WaitOne();
// printSecond() outputs "second". Do not change or remove this line.
while(sec==false);
printSecond();
thi=true;
//third.Set();
}
public void Third(Action printThird) {
while(thi==false);
//third.WaitOne();
// printThird() outputs "third". Do not change or remove this line.
printThird();
}
}
2020.10.27,份就到这里,未完待续
2020.10.28,份开始了
因为上面两个执行效率有点低,所以采用更好方式,用auto以及mu那个都会超时
今天介绍信号量机制,就是那个操作系统里面的信号量
SemaphoreSlim
使用大概三个流程
创建:
private SemaphoreSlim ht = new SemaphoreSlim(2, 2);
private SemaphoreSlim ht = new SemaphoreSlim(2);
//第一个2表示最大初始数量,第二个2表示最大数量
使用信号量也就是信号量减一:
ht.Wait();
信号量释放也就是信号量加一
ht.Release();
1116:
源码:
using System.Threading;
public class ZeroEvenOdd {
private int n;
private SemaphoreSlim first = new SemaphoreSlim(1, 1);
private SemaphoreSlim second = new SemaphoreSlim(0, 1);
private SemaphoreSlim third = new SemaphoreSlim(0, 1);
public ZeroEvenOdd(int n) {
this.n = n;
}
// printNumber(x) outputs "x", where x is an integer.
public void Zero(Action<int> printNumber) {
for(int i=1;i<=n;i++)
{
first.Wait();
printNumber(0);
if(i%2==0)
{
second.Release();
}
else
{
third.Release();
}
}
}
public void Even(Action<int> printNumber) {
for(int i=2;i<=n;i+=2)
{
second.Wait();
printNumber(i);
first.Release();
}
}
public void Odd(Action<int> printNumber) {
for(int i=1;i<=n;i+=2)
{
third.Wait();
printNumber(i);
first.Release();
}
}
}
1117:
源码:
using System.Threading;
public class H2O {
private SemaphoreSlim ot = new SemaphoreSlim(0, 1);
private SemaphoreSlim ht = new SemaphoreSlim(2, 2);
public H2O() {
}
public void Hydrogen(Action releaseHydrogen) {
ht.Wait();
// releaseHydrogen() outputs "H". Do not change or remove this line.
releaseHydrogen();
if(ht.CurrentCount==0)
ot.Release();
}
public void Oxygen(Action releaseOxygen) {
ot.Wait();
// releaseOxygen() outputs "O". Do not change or remove this line.
releaseOxygen();
ht.Release(2);
}
}