C#线程:竞争条件的例子 [英] C# Threading: a race condition example

查看:174
本文介绍了C#线程:竞争条件的例子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读 http://www.mono-project.com/ThreadsBeginnersGuide



第一个例子是这样的:

 公共类FirstUnsyncThreads {
私人INT I = 0;

公共静态无效的主要(字串[] args){
FirstUnsyncThreads myThreads =新FirstUnsyncThreads();
}

公共FirstUnsyncThreads(){
//创建我们的两个线程。 ThreadStart委托是指向
//在一个新的线程中运行的方法。
螺纹firstRunner =新主题(新的ThreadStart(this.firstRun));
螺纹secondRunner =新主题(新的ThreadStart(this.secondRun));

//开始我们两个线程。 Thread.sleep代码(10)给人的第一主题
// 10毫秒更多的时间。
firstRunner.Start();
Thread.sleep代码(10);
secondRunner.Start();
}

//此方法被excecuted第一个线程。
公共无效firstRun(){
,而(this.i小于10){
Console.WriteLine(亚军从增加i+ this.i +
按钮+ ++ this.i);
//这避免了亚军确实之前
所有的工作//第二个甚至开始。 (高性能
//机器有时会发生。)
Thread.sleep代码(100);
}
}

//此方法被excecuted第二个线程。
公共无效secondRun(){
,而(this.i小于10){
Console.WriteLine(季军递增,我从+ this.i +
按钮+ ++ this.i);
Thread.sleep代码(100);
}
}
}



输出:



 亚军递增我从0到1 
季军增加i从1到2
季军3递增我4
亚军递增,我从2到3
季军1名5至6
亚军递增,我从4至5
亚军增加i增加i从6到7
季军递增,我从7至8
季军1名9至10
亚军递增,我从8日至9
增加i

哇,这是什么?不幸的是,在文章中的解释是不够的我。你能解释我为什么增量在一个混乱的秩序发生了什么?



谢谢!


解决方案

我觉得文章的作家困惑的事情。



VoteyDisciple是正确的 ++我是不是原子的,如果目标没有在操作过程中被锁定,但这不会造成上述问题可能出现争用条件。



如果出现竞争状态调用 ++我 ++ 运营商看起来像,那么内部操作: -




  1. 第一个线程读取值0

  2. 第二线程读取值0

  3. 1号线增量值1

  4. 第二线程的增量值1

  5. 第一个线程写入值1

  6. 第二线程写入值1



  7. 操作3至6中的顺序是不重要的,该点是,无论是读操作,图1和2,可发生当变量具有产生在相同的增量为y,而不是每一个线程执行用于x和y的不同值incrementations值x



    这可能会导致下面的输出 -

     亚军从0递增i到1 
    季军从0到1
    增加i

    什么是更糟糕的是以下几点: -




    1. 第一个线程读取值0

    2. 第二线程读取值0

    3. 第二线程的增量值1

    4. 第二线程写入值1

    5. 第二线程读取值1

    6. 第二线程的增量值2

    7. 第二线程值2

    8. 第一个线程的增量值写入1

    9. 第一个线程写入值1

    10. 第2个线程读取值1

    11. 第二线程的增量值2

    12. 第二线程写入值2



    这可能会导致如下输出: -

     亚军从0到1 
    季军增加i从0到1
    季军增加i从1到2
    季军增加i从1到2
    增加i

    和等。



    此外,还有阅读之间可能存在竞争条件 I 并执行 ++我因为Console.WriteLine命令调用会连接 I ++我。这可能会导致类似的输出: -

     亚军递增我从0到1 
    季军1递增我3
    亚军增加i从1到2

    冗杂控制台输出,作家描述了只能从控制台输出的不可预测性导致并有无关的竞争条件上的 I 变量。采取锁 I 而执行 ++我或同时串联 I ++我不会改变这一行为。


    I am reading http://www.mono-project.com/ThreadsBeginnersGuide.

    The first example looks like this:

    public class FirstUnsyncThreads {
    	private int i = 0;
    
    	public static void Main (string[] args) {
    		FirstUnsyncThreads myThreads = new FirstUnsyncThreads ();
    	}
    
    	public FirstUnsyncThreads () {
    		// Creating our two threads. The ThreadStart delegate is points to
    		// the method being run in a new thread.
    		Thread firstRunner = new Thread (new ThreadStart (this.firstRun));
    		Thread secondRunner = new Thread (new ThreadStart (this.secondRun));
    
    		// Starting our two threads. Thread.Sleep(10) gives the first Thread
    		// 10 miliseconds more time.
    		firstRunner.Start ();
    		Thread.Sleep (10);
    		secondRunner.Start ();
    	}
    
    	// This method is being excecuted on the first thread.
    	public void firstRun () {
    		while(this.i < 10) {
    			Console.WriteLine ("First runner incrementing i from " + this.i +
    			                  " to " + ++this.i);
    			// This avoids that the first runner does all the work before
    			// the second one has even started. (Happens on high performance
    			// machines sometimes.)
    			Thread.Sleep (100);
    		}
    	}
    
    	// This method is being excecuted on the second thread.
    	public void secondRun () {
    		while(this.i < 10) {
    			Console.WriteLine ("Second runner incrementing i from " + this.i +
    			                  " to " + ++this.i);
    			Thread.Sleep (100);
    		}
    	}
    }
    

    Output:

    First runner incrementing i from 0 to 1
    Second runner incrementing i from 1 to 2
    Second runner incrementing i from 3 to 4
    First runner incrementing i from 2 to 3
    Second runner incrementing i from 5 to 6
    First runner incrementing i from 4 to 5
    First runner incrementing i from 6 to 7
    Second runner incrementing i from 7 to 8
    Second runner incrementing i from 9 to 10
    First runner incrementing i from 8 to 9
    

    Wow, what is this? Unfortunately, the explanation in the article is inadequate for me. Can you explain me why the increments happened in a jumbled order?

    Thanks!

    解决方案

    I think the writer of the article has confused things.

    VoteyDisciple is correct that ++i is not atomic and a race condition can occur if the target is not locked during the operation but this will not cause the issue described above.

    If a race condition occurs calling ++i then internal operations of the ++ operator will look something like:-

    1. 1st thread reads value 0
    2. 2nd thread reads value 0
    3. 1st thread increments value to 1
    4. 2nd thread increments value to 1
    5. 1st thread writes value 1
    6. 2nd thread writes value 1

    The order of operations 3 to 6 is unimportant, the point is that both the read operations, 1 and 2, can occur when the variable has value x resulting in the same incrementation to y, rather than each thread performing incrementations for distinct values of x and y.

    This may result in the following output:-

    First runner incrementing i from 0 to 1
    Second runner incrementing i from 0 to 1
    

    What would be even worse is the following:-

    1. 1st thread reads value 0
    2. 2nd thread reads value 0
    3. 2nd thread increments value to 1
    4. 2nd thread writes value 1
    5. 2nd thread reads value 1
    6. 2nd thread increments value to 2
    7. 2nd thread writes value 2
    8. 1st thread increments value to 1
    9. 1st thread writes value 1
    10. 2nd thread reads value 1
    11. 2nd thread increments value to 2
    12. 2nd thread writes value 2

    This may result in the following output:-

    First runner incrementing i from 0 to 1
    Second runner incrementing i from 0 to 1
    Second runner incrementing i from 1 to 2
    Second runner incrementing i from 1 to 2
    

    And so on.

    Furthermore, there is a possible race condition between reading i and performing ++i since the Console.WriteLine call concatenates i and ++i. This may result in output like:-

    First runner incrementing i from 0 to 1
    Second runner incrementing i from 1 to 3
    First runner incrementing i from 1 to 2
    

    The jumbled console output which the writer has described can only result from the unpredictability of the console output and has nothing to do with a race condition on the i variable. Taking a lock on i whilst performing ++i or whilst concatenating i and ++i will not change this behaviour.

    这篇关于C#线程:竞争条件的例子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆