2015-04-29 3 views
0

Я думаю, что когда я начинаю свой первый поток, он должен печатать «один + n» и блокировать l, после чего он должен запустить второй поток и напечатать «two + п».использование ключевого слова lock по различным темам

Что на самом деле происходит, является то, что, когда я запускаю программу, я получаю случайные результаты, иногда печать «один + N», в другое время печати «два + п»

Мое понимание этого, очевидно, недостатки - почему?

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace ConsoleApplication1 
{ 
class locked 
{ 
    public long numtochange { get; set; } 
    public string threadname { get; set; } 
} 

class Program 
{ 
    public static locked l; 

    static void Main(string[] args) 
    { 
     l = new locked(); 

     (new Thread(x => { l.threadname = "one"; Print(l); })).Start(); 


     (new Thread(x => { l.threadname = "two"; Print(l); })).Start(); 

     Console.ReadLine(); 
    } 
    public static void Print(locked l) 
    { 
     lock (l) 
     { 
      for (long i = 0; i < 1000; i++) 
      { 
       l.numtochange = i; 
       Console.WriteLine(l.threadname + " " + l.numtochange); 
      } 
     }  
    } 
} 
} 
+0

Вы как-то получили ответ, но не понимая своего мышления, трудно объяснить вашу ошибку. * Почему * вы думаете, что программа напечатает то, что вы предсказали? – usr

ответ

5

Эта часть кода:

l.threadname = "one"; 

и соответствующая одна с = "two" не заблокированы. Следовательно, они могут чередоваться случайным образом - иногда строка "one" заканчивается в l.threadname, а иногда она переписывается "two". Затем первый поток, которому удается перейти к оператору lock в функции Print, выполняет свою работу, а другая ждет.

Самым простым способом исправить, если вы хотите, чтобы работать последовательно, чтобы обернуть оба заявления с lock ключевого слова, например:

lock (l) { l.threadname = "one"; Print(l); } 

(lock реентерабелен, так что не будет никаких проблем с другим lock в Print).

Однако, если они всегда работают один за другим, нет смысла использовать потоки.

+2

это можно визуализировать, если вы распечатываете идентификатор потока 'Console.WriteLine (l.threadname +" "+ l.numtochange +" "+ Thread.CurrentThread.ManagedThreadId);' –

Смежные вопросы