C# nie pozwala na blokowanie wartości pustej. Przypuszczam, że mógłbym sprawdzić, czy wartość jest zerowa, czy nie, zanim ją zablokuję, ale ponieważ nie zablokowałem jej, może pojawić się kolejny wątek i wartość zerowa! Jak mogę uniknąć tego wyścigu?Dlaczego C# nie pozwala na zablokowanie wartości pustej?
Odpowiedz
Zablokuj wartość, która nigdy nie jest pusta, np.
Object _lockOnMe = new Object();
Object _iMightBeNull;
public void DoSomeKungFu() {
if (_iMightBeNull == null) {
lock (_lockOnMe) {
if (_iMightBeNull == null) {
_iMightBeNull = ... whatever ...;
}
}
}
}
Należy także uważać, aby uniknąć tego ciekawą sytuację wyścigu ze Blokada z podwójnym zatwierdzeniem: Memory Model Guarantees in Double-checked Locking
Może być miło dodać tylko do obiektu blokady, aby wywołać żądaną niezmienność – cordialgerm
, dlaczego blokowanie _lockOnMe może uniemożliwić innym dostęp do _iMightBeNull? –
-1: Twój kod jest nadal podatny na warunki wyścigu, z którymi się łączyłeś; '_iMightBeNull' musi być zadeklarowany jako zmienny. Lub, najlepiej, należy po prostu użyć 'Lazy
Istnieją dwa problemy tutaj:
Po pierwsze, nie blokuj na null
obiektu. To nie ma sensu, jak można rozróżnić dwa obiekty, zarówno te, jak i obiekty?
drugie, aby bezpiecznie zainicjalizować zmienną w środowisku wielowątkowym, użyj dwukrotnie sprawdzane wzór blokowania:
if (o == null) {
lock (lockObj) {
if (o == null) {
o = new Object();
}
}
}
To zapewni, że inny wątek nie został już zainicjowany obiekt i mogą być wykorzystane do wdrożenia Wzór Singleton.
Nie można zablokować na wartość null, ponieważ CLR nie ma miejsca do zamocowania SyncBlock się, co jest, co pozwala CLR do synchronizowania dostępu do dowolnych obiektów poprzez Monitor.Enter/Exit (czego lock
używa wewnętrznie)
+1: To jest najbardziej poprawna odpowiedź. –
Dlaczego C# nie pozwala na zablokowanie wartości pustej?
Paul's answer to jedyny poprawny technicznie do tej pory, więc zaakceptowałbym to. Dzieje się tak dlatego, że monitory w .NET używają bloku synchronizacji, który jest dołączony do wszystkich typów referencji. Jeśli masz zmienną, która jest null
, to nie odnosi się ona do żadnego obiektu, a to oznacza, że monitor nie ma dostępu do użytecznego bloku synchronizacji.
Jak mogę uniknąć tego stanu wyścigu?
Tradycyjne podejście jest, aby zablokować na odwołania do obiektu, który wiesz, nigdy nie będzie null
. Jeśli znajdziesz się w sytuacji, w której nie można tego zagwarantować, sklasyfikuję to jako podejście nietradycyjne. Naprawdę nie ma o wiele więcej, o czym mogę tutaj wspomnieć, chyba że opiszę bardziej szczegółowo konkretny scenariusz, który może prowadzić do zerowych celów blokowania.
Pierwsza część pytania została już odebrana, ale chciałbym dodać coś do drugiej części pytania.
Łatwiej jest użyć innego obiektu do wykonania blokady, szczególnie w tym stanie. Rozwiązuje to również problem utrzymywania stanów wielu obiektów udostępnionych w sekcji krytycznej, np. lista pracowników i lista zdjęć pracowników.
Ponadto technika ta jest również przydatna, gdy trzeba nabyć blokadę na prymitywnych typów np int lub dziesiętny itp
Moim zdaniem jeśli użyć tej techniki jak wszyscy inni sugerowane wtedy nie trzeba wykonywać zerowa kontrola dwa razy. na przykładw zaakceptowanej odpowiedzi Cris użył warunku dwa razy, który tak naprawdę nie robi żadnej różnicy, ponieważ zablokowany obiekt jest inny niż to, co jest aktualnie modyfikowane, jeśli blokujesz inny obiekt, to wykonanie pierwszego zerowego czeku jest bezużyteczne i marnowanie procesora .
Proponuję następujący fragment kodu;
object readonly syncRootEmployee = new object();
List<Employee> employeeList = null;
List<EmployeePhoto> employeePhotoList = null;
public void AddEmployee(Employee employee, List<EmployeePhoto> photos)
{
lock (syncRootEmployee)
{
if (employeeList == null)
{
employeeList = new List<Employee>();
}
if (employeePhotoList == null)
{
employeePhotoList = new List<EmployeePhoto>();
}
employeeList.Add(employee);
foreach(EmployeePhoto ep in photos)
{
employeePhotoList.Add(ep);
}
}
}
Nie widzę tutaj żadnego stanu wyścigu, jeśli ktoś inny zobaczy stan wyścigu, proszę o odpowiedź w komentarzach. Jak widać w powyższym kodzie, rozwiązuje on 3 problem naraz, jeden nie wymaga kontroli zerowej przed blokowaniem, drugi tworzy sekcję krytyczną bez blokowania dwóch współdzielonych źródeł, a trzecie blokowanie więcej niż jednego obiektu powoduje zakleszczenia z powodu braku uwagi podczas pisania kod.
Oto jak używam zamków w typach pierwotnych.
object readonly syncRootIteration = new object();
long iterationCount = 0;
long iterationTimeMs = 0;
public void IncrementIterationCount(long timeTook)
{
lock (syncRootIteration)
{
iterationCount++;
iterationTimeMs = timeTook;
}
}
public long GetIterationAvgTimeMs()
{
long result = 0;
//if read without lock the result might not be accurate
lock (syncRootIteration)
{
if (this.iterationCount > 0)
{
result = this.iterationTimeMs/this.iterationCount;
}
}
return result;
}
Szczęśliwy gwintowania :)
- 1. Dlaczego C++ nie pozwala mi używać typeof?
- 2. Dlaczego próba dodania wartości pustej nie powoduje wyjątku InvalidOperationException?
- 3. Konstruktor Webservice C# nie pozwala na argumenty?
- 4. Filtr aspektów Algolia według pustej/pustej wartości
- 5. ASP.NET nie może buforować wartości pustej
- 6. Dlaczego Visual C++ 2015 pozwala na std :: atomowe przypisanie?
- 7. Łatwiejszy sposób zapisu wartości pustej lub pustej?
- 8. Dlaczego C++ pozwala na przypisanie liczby całkowitej do ciągu?
- 9. Dlaczego PHPExcel nie pozwala na zapisanie więcej niż 5000 wierszy
- 10. Dlaczego drzewo map Java Java nie pozwala na początkowy rozmiar?
- 11. Dlaczego Rust nie pozwala na wymuszanie obiektów w kontenerach?
- 12. Dlaczego seq computation builder nie pozwala na "let!"
- 13. Dlaczego JavaScript nie pozwala na przypisanie właściwości "nazwa" do funkcji?
- 14. Dlaczego moja HashMap pozwala na duplikowanie kluczy?
- 15. Dokładny sposób sprawdzenia, czy zestaw nie zawiera wartości pustej
- 16. Jak sprawdzić var dla wartości pustej?
- 17. Jak mogę sprawdzić/null pustej wartości cshtml
- 18. Dlaczego TypeScript pozwala konwertować z ciągu na numer bez ostrzeżenia
- 19. Szukaj rubin hash dla wartości pustej
- 20. Dlaczego Python pozwala na tworzenie słowników z duplikatami kluczy
- 21. Drukowanie na standardowe wyjście powoduje zablokowanie goroutiny?
- 22. Zablokowanie gniazda zwraca EAGAIN
- 23. Dlaczego moje ograniczenie sprawdzające nie zatrzymuje tej pustej wkładki?
- 24. Test pustej wartości uniwersalny dla wszystkich typów
- 25. Entity Framework: Aktualizowanie pola do wartości pustej?
- 26. ustawiania wartości opcji HTML do pustej struny
- 27. ALTER TABLE nie pozwala ustawić wartości NULL lub domyślnej?
- 28. Kontrola Select2, pozwala na wielokrotne wybieranie tej samej wartości
- 29. JMSSerializerBundle Wyświetl pustą wartość zamiast wartości pustej
- 30. Wykrywanie wartości pustej/pustego wejścia od użytkownika
Dlaczego nie można po prostu użyć człon że zainicjowany statycznie i * nie zawsze jest null * – zerkms
Jak rozumiem, null jest w zasadzie nic. Jak możesz zablokować nic? Innymi słowy, ciąg myString = null deklaruje zmienną typu string, ale to wszystko jest do niego - nie istnieje jako obiekt, ponieważ nie ma wartości. – Tim