2016-02-24 2 views
-4

Я использую VS2010 .Net 4.0, поэтому я не могу использовать вызовы await. У меня есть один поток, загружающий что-то, и я не должен продолжать, пока статус не станет «Готово». Поэтому я использую цикл while, блокирующий поток. Но каким-то образом он становится бесконечным циклом. Правильно ли я создаю нить?Почему цикл нитки бесконечно?

string status = string.Empty; 
Thread thread = new System.Threading.Thread(() => 
{ 
    status = Download(downloadKit, patchTitle); 
}); 
thread.Start(); 
thread.Join(); 

// Loops here forever 
while (status != "Done") 
{ 
    //Thread.Sleep(25); // Tried this as well, same result 
    Thread.SpinWait(1); 
} 
+0

Наверное, потому что «статус» никогда не будет иметь шансов на изменение. – CollinD

+0

Установите точку останова (F9) в инструкции Status = download и повторно запустите свою программу. Когда вы нажмете этот оператор, нажмите F11 на один шаг в методе загрузки. –

+1

, мы должны быть уверены, что код загрузки вернется в определенный момент. Я полагаю, это не так. – pm100

ответ

0

Вам нужно понять, что блокирует в вызывающей нити thread.Join(); до тех пор, пока нить, которая будет соединена, не будет завершена. Как только вы это поймете, вы увидите, что глупо делать цикл while в вызывающем потоке над значением статуса, как если бы вы передали соединение, тогда значение статуса никогда не изменится, если вы не добавите код, который делает это.

string status = string.Empty; 
Thread thread = new System.Threading.Thread(() => 
{ 
    status = Download(downloadKit, patchTitle); 
}); 
thread.Start(); 
thread.Join(); 

//no point in looping here, if the thread finished, it has already assigned the 
//value it is going to assign to the status variable 
if (status == "Done") 
{ 
    //do what needs to be done 
} 
else 
{ 
    //uh oh, handle the failure here 
} 

Для решения требования, что вы не можете продолжать до status=="Done", вы могли бы вместо того, чтобы поместить время цикла внутри дочернего потока таким образом, что он продолжает пытаться функцией загрузки, пока он не вернется «Done»:

string status = string.Empty; 
Thread thread = new System.Threading.Thread(() => 
{ 
    while(status != "Done") 
     status = Download(downloadKit, patchTitle); 
}); 
thread.Start(); 
thread.Join(); 

//do what needs to be done 
0

Threading может привести к некоторым странным вещам иногда, вам нужно иногда сказать компилятору, что вы что-то небезопасное предварительной формовку, вы можете сделать это, делая var nstatus = Volatile.Read(ref status), а затем сравнить против этого.

string nstatus = status; 
// Loops here forever 
while (nstatus != "Done") 
{ 
    //Thread.Sleep(25); // Tried this as well, same result 
    Thread.SpinWait(1); 
    nstatus = Volatile.Read(ref status); 
} 

Другой альтернативой является использование Thread.MemoryBarrier() вызова (который я считаю, что делается в энергозависимой вызова), который предотвращает изменение порядка отчетности компилятором:

// Loops here forever 
while (status != "Done") 
{ 
    //Thread.Sleep(25); // Tried this as well, same result 
    Thread.SpinWait(1); 
    Thread.MemoryBarrier(); 
} 

Хороший ресурс, чтобы посмотреть at будет http://www.albahari.com/threading/part4.aspx, очень подробно посмотрите на Threading в .NET 4.0