加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

C#线程安全使用(三)

发布时间:2020-12-15 04:46:17 所属栏目:百科 来源:网络整理
导读:在讲CancellationTokenSource之前我决定先讲一下lock和Interlocked,如果能很好的理解这两个,再去理解CancellationTokenSource就会方便很多,由于我也是后起使用多线程,使用的时候就是直接运用FramWork4的东西,这样导致了很多东西学起来很吃力,当回顾了

在讲CancellationTokenSource之前我决定先讲一下lock和Interlocked,如果能很好的理解这两个,再去理解CancellationTokenSource就会方便很多,由于我也是后起使用多线程,使用的时候就是直接运用FramWork4的东西,这样导致了很多东西学起来很吃力,当回顾了以前的知识点后,发现新出的东西如此好理解。

先看一下Lock的使用,下面是一个例子。

<span style="color: #0000ff;">namespace<span style="color: #000000;"> LockConsole
{
<span style="color: #0000ff;">class
<span style="color: #000000;"> Program
{
<span style="color: #0000ff;">static
<span style="color: #0000ff;">object
lockint = <span style="color: #800080;">0
<span style="color: #000000;">;
<span style="color: #0000ff;">static
<span style="color: #0000ff;">void
<span style="color: #000000;"> Main()
{
Task[] tlist
=<span style="color: #0000ff;">new Task[<span style="color: #800080;">10<span style="color: #000000;">];

        Thread[] threads </span>= <span style="color: #0000ff;"&gt;new</span> Thread[<span style="color: #800080;"&gt;10</span><span style="color: #000000;"&gt;];

        </span><span style="color: #0000ff;"&gt;for</span> (<span style="color: #0000ff;"&gt;int</span> i = <span style="color: #800080;"&gt;0</span>; i < <span style="color: #800080;"&gt;10</span>; i++<span style="color: #000000;"&gt;)
        {
         </span><span style="color: #0000ff;"&gt;var</span> action =   <span style="color: #0000ff;"&gt;new</span> Action<<span style="color: #0000ff;"&gt;object</span>><span style="color: #000000;"&gt;(Withdraw);
         Task t </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; Task(action,i);
         tlist[i] </span>=<span style="color: #000000;"&gt; t;
            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;Thread t = new Thread(new ThreadStart(acc.DoTransactions));
            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;threads[i] = t;</span>

<span style="color: #000000;"> }
<span style="color: #0000ff;">for (<span style="color: #0000ff;">int i = <span style="color: #800080;">0; i < <span style="color: #800080;">10; i++<span style="color: #000000;">)
{
tlist[i].Start();

            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;threads[i].Start();</span>

<span style="color: #000000;"> }
Console.Read();
}

    </span><span style="color: #0000ff;"&gt;static</span> <span style="color: #0000ff;"&gt;void</span> Withdraw(<span style="color: #0000ff;"&gt;object</span><span style="color: #000000;"&gt; i)
    {
        </span><span style="color: #0000ff;"&gt;int</span> amount = <span style="color: #0000ff;"&gt;int</span><span style="color: #000000;"&gt;.Parse(i.ToString());
        </span><span style="color: #0000ff;"&gt;int</span>  balance = <span style="color: #800080;"&gt;1000</span><span style="color: #000000;"&gt;;

        </span><span style="color: #0000ff;"&gt;lock</span> (lockint)<span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;删除lock就会造成 线程混乱</span>

<span style="color: #000000;"> {
<span style="color: #0000ff;">if (balance >=<span style="color: #000000;"> amount)
{
Console.WriteLine(<span style="color: #800000;">"<span style="color: #800000;">当前线程{0},当前状态{1}<span style="color: #800000;">",Thread.CurrentThread.GetHashCode(),Thread.CurrentThread.ThreadState + <span style="color: #800000;">"<span style="color: #800000;">Balance before Withdrawal : <span style="color: #800000;">" +<span style="color: #000000;"> balance);
Console.WriteLine(<span style="color: #800000;">"<span style="color: #800000;">当前线程{0},Thread.CurrentThread.ThreadState + <span style="color: #800000;">"<span style="color: #800000;">Amount to Withdraw : -<span style="color: #800000;">" +<span style="color: #000000;"> amount);
balance = balance -<span style="color: #000000;"> amount;
Console.WriteLine(<span style="color: #800000;">"<span style="color: #800000;">当前线程{0},Thread.CurrentThread.ThreadState + <span style="color: #800000;">"<span style="color: #800000;">Balance after Withdrawal : <span style="color: #800000;">" +<span style="color: #000000;"> balance);

            }

        }
    }



}

}

输出结果如下,他的线程都是一个接一个的,线程11后是线程12,然后是13,14,11等。每个线程都是等到执行完了下一个才执行。

?

在看一下没有Lock的结果,如下图,线程是混乱的,12线程的函数没执行完13就开始了。

有了上面的例子,Lock就很好理解了,他是为了保障资源同一时间只被一个线程使用,虽然该例子中没有使用Lock的资源,但线程还是一个接一个的执行,因为使用了lock线程就会一个接一个执行。

接下来看一下interLock,这是一个MSDN的例子,我觉得不错,他的意思是,把usingResource作为一个锁,当多线程开始运行,函数UseResource()需要判断usingResource的值,当usingResource等于0的时候,当前线程不运行,否则运行,当本线程运行时,要修改usingResource的值为1,这样确保其他线程不运行,即同一时间只运行一个线程。

如果这样需求用到开发中,会出现一个问题,那就是当一个线程改变usingResource的值的一瞬间,别的线程读取了usingResource的值,那这个线程也被运行了。

这时就需要InterLock了。代码如下。

<span style="color: #0000ff;">namespace<span style="color: #000000;"> MyInterlockedExchangeExampleClass
{
<span style="color: #0000ff;">class
<span style="color: #000000;"> MyInterlockedExchangeExampleClass
{
<span style="color: #008000;">//
<span style="color: #008000;">0 for false,1 for true.

<span style="color: #0000ff;">private
<span style="color: #0000ff;">static
<span style="color: #0000ff;">int
usingResource = <span style="color: #800080;">0
<span style="color: #000000;">;

    </span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;const</span> <span style="color: #0000ff;"&gt;int</span> numThreadIterations = <span style="color: #800080;"&gt;5</span><span style="color: #000000;"&gt;;
    </span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;const</span> <span style="color: #0000ff;"&gt;int</span> numThreads = <span style="color: #800080;"&gt;10</span><span style="color: #000000;"&gt;;

    </span><span style="color: #0000ff;"&gt;static</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; Main()
    {
        Thread myThread;
        Random rnd </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; Random();

        </span><span style="color: #0000ff;"&gt;for</span> (<span style="color: #0000ff;"&gt;int</span> i = <span style="color: #800080;"&gt;0</span>; i < numThreads; i++<span style="color: #000000;"&gt;)
        {
            myThread </span>= <span style="color: #0000ff;"&gt;new</span> Thread(<span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; ThreadStart(MyThreadProc));
            myThread.Name </span>= String.Format(<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;Thread{0}</span><span style="color: #800000;"&gt;"</span>,i + <span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;);

            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;Wait a random amount of time before starting next thread.</span>
            Thread.Sleep(rnd.Next(<span style="color: #800080;"&gt;0</span>,<span style="color: #800080;"&gt;1000</span><span style="color: #000000;"&gt;));
            myThread.Start();
        }
    }

    </span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;static</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; MyThreadProc()
    {
        </span><span style="color: #0000ff;"&gt;for</span> (<span style="color: #0000ff;"&gt;int</span> i = <span style="color: #800080;"&gt;0</span>; i < numThreadIterations; i++<span style="color: #000000;"&gt;)
        {
            UseResource();

            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;Wait 1 second before next attempt.</span>
            Thread.Sleep(<span style="color: #800080;"&gt;1000</span><span style="color: #000000;"&gt;);
        }
    }

    </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;A simple method that denies reentrancy.</span>
    <span style="color: #0000ff;"&gt;static</span> <span style="color: #0000ff;"&gt;bool</span><span style="color: #000000;"&gt; UseResource()
    {
        </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;0 indicates that the method is not in use.
        </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;原始值是0,判断是时候使用原始值,但判断后值为1,进行了设置</span>
        <span style="color: #0000ff;"&gt;if</span> (<span style="color: #800080;"&gt;0</span> == Interlocked.Exchange(<span style="color: #0000ff;"&gt;ref</span> usingResource,<span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;))
        {
            Console.WriteLine(</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;{0} acquired the lock</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,Thread.CurrentThread.Name);

            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;Code to access a resource that is not thread safe would go here.

            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;Simulate some work</span>
            Thread.Sleep(<span style="color: #800080;"&gt;500</span><span style="color: #000000;"&gt;);

            Console.WriteLine(</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;{0} exiting lock</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,Thread.CurrentThread.Name);

            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;Release the lock</span>
            Interlocked.Exchange(<span style="color: #0000ff;"&gt;ref</span> usingResource,<span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;);
            </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;true</span><span style="color: #000000;"&gt;;
        }
        </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt;
        {
            Console.WriteLine(</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;   {0} was denied the lock</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,Thread.CurrentThread.Name);
            </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;false</span><span style="color: #000000;"&gt;;
        }
    }

}

}

理解了lock和interlock后下一章讲解CancellationTokenSource。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读