2015-11-10 2 views
0

Моя идея - запустить несколько операций асинхронно; Я могу гарантировать, что две операции никогда не будут выполняться одновременно, но я не могу гарантировать, что они будут работать в одном потоке/ЦП, как и другие.Требуется блокировка, когда только один поток получает доступ к значению за раз?

// Example code 
int myValue = 0; 

ThreadPool.QueueUserWorkItem(state => { 
    myValue++; 

    ThreadPool.QueueUserWorkItem(state2 => { 
     Console.WriteLine(myValue); 
    }); 
}); 

Гарантирует ли выход быть 1 даже без блокировки?

Возможно, требуется позвонить Thread.MemoryBarrier() до Console.WriteLine(myValue)?

Или возможно myValue должно быть сделано volatile?

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

Спасибо!

EDIT:

Что делать, если я решу использовать блокировку? Является ли этот код гарантией вывода 1?

Если да, то почему? Не удалось компилятору сохранить myValue в регистре CPU?

У меня никогда не было проблем с таким кодом, но я только запускал свои программы на процессорах x86 и x64. Что относительно MONO, ARM и других «эзотерических» платформ?

// Example code 
object lockMe = new object(); 
int myValue = 0; 

ThreadPool.QueueUserWorkItem(state => { 
    lock(lockMe) { 
     myValue++; 
    } 

    ThreadPool.QueueUserWorkItem(state2 => { 
     lock(lockMe) { 
      Console.WriteLine(myValue); 
     } 
    }); 
}); 

Еще раз спасибо!

+0

'Console.WriteLine (myValue);' всегда будет печатать '1'. Но имейте в виду, что он не гарантирует, что 'myValue' уже будет увеличен после выполнения' ThreadPool.QueueUserWorkItem (...); ' – nozzleman

+1

To" Или, может быть, 'myValue' должен быть сделан' volatile'? " - http://stackoverflow.com/a/17530556/2026276 – Bauss

+0

@nozzleman Могу ли я спросить, как можно гарантировать, что вторая операция ('Console.WriteLine') увидит обновленную версию' myValue'? Может ли 'myValue' не кэшироваться в регистре CPU, который выполнил первую операцию (' myValue ++ ')? Простите мою неопределенность. –

ответ

1

ThreadPool.QueueUserWorkItem, как любые другие функции библиотеки, которая выполняет код в другом потоке, ГАРАНТИЯ, что этот код будет видеть все изменения, видимых в текущем потоке до вызова функции.

Поскольку myValue++ предшествует ThreadPool.QueueUserWorkItem()в программном порядке, результат изменения значения в видно в потоке вызывающего абонента. Таким образом, Console.WriteLine(myValue) обязательно увидит обновленное значение.

Блокировка, изменчивый модификатор в этом случае совершенно не нужен.

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