У чым розніца паміж бяспечнай ніткай і атамнай?


адказ 1:

Надзейная нітка азначае, што пры доступе да некалькіх тэм няма праблем. Атам азначае непадзельнае, у гэтым кантэксце сінонім бесперапыннага.

Ёсць два спосабы рэалізацыі замкаў:

  1. Апаратная падтрымка атамных аперацый - спецыяльныя складаныя інструкцыі, якія выконваюцца ў цэлым, напрыклад B. Test-and-set.Be разумны (і нясе на сабе наступствы) - алгарытм Пітэрсана.

У вашым дэталёвым прыкладзе абодва не ўпэўненыя. калі я правільна разумею, вы маеце на ўвазе нешта падобнае:

public class Unsure {private object ulock = new object (); public int Unsafe1 {атрымаць; наладзіць; } = 0; прыватны int _unsafe2 = 0; public int Unsafe2 {get {lock (ulock) {return _unsafe2; }} усталяваць {lock (адмыканне) {_unsafe2 = значэнне; }}}}

Код тэсту:

var u = новы небяспечны (); Parallel.For (0, 10000000, _ => {u.Unsafe1 ++;}); Parallel.For (0, 10000000, _ => {u.Unsafe2 ++;}); Console.WriteLine (string.Format ("{0} - {1}", u.Unsafe1, u.Unsafe2));

Вынік (адзін з мноства магчымых):

4648265 - 4149827

У абодвух выпадках больш за палову абнаўленняў зніклі.

Прычынай гэтага з'яўляецца тое, што ++ не з'яўляецца атамным - на самай справе ёсць тры асобныя аперацыі:

  1. Атрымаеце value.Add 1 to value.Set value.

Мы можам гэта выправіць, забяспечыўшы атамную паступовую аперацыю. Ёсць шмат спосабаў зрабіць гэта, але вось два:

public class Safe {private object slock = new object (); public int Safe1 {атрымаць; наладзіць; } публічная несапраўдная SafeIncrement1 () {замак (разблакіроўка) {this.Safe1 ++; }} private int _safe2 = 0; public int Safe2 {get {return _safe2; } ўсталяваць {_safe2 = значэнне; }} публічная несапраўдная SafeIncrement2 () {Interlocked.Increment (ref _safe2); }}

Код тэсту:

var s = new Safe (); Parallel.For (0, 10000000, _ => {am SafeIncrement1 ();}); Parallel.For (0, 10000000, _ => {am SafeIncrement2 ();}); Console.WriteLine (string.Format ("{0} - {1}", на Safe1, на Safe2));

Вынікі ў абодвух выпадках правільныя. Першы проста фіксуе ўсю аперацыю Composite ++, а другі выкарыстоўвае апаратную падтрымку для атамных аперацый.

Звярніце ўвагу, што другі варыянт вышэй з Interlocked.Increment значна хутчэй, але на самай справе мае больш нізкі ўзровень і прапануе толькі абмежаваную функцыянальнасць. Аднак аперацыі ў заблакаваным пакеце могуць быць выкарыстаны для рэалізацыі наступнага:

  1. Вядомыя замкі, вядомыя як "песімістычны паралелізм", таму што яны мяркуюць, што працэс будзе перапынены, не пачынаюцца, пакуль яны не набываюць агульны рэсурс. Параўноўваючы і абменьваючыся, выкарыстоўвайце спецыяльнае значэнне "Канары", якое вы запісваеце ў пачатку, і пераканайцеся, што ў выніку нічога не змянілася. Ідэя заключаецца ў тым, што іншая нітка забівае канарку, каб вы ведалі, што вам трэба будзе паўтарыць транзакцыю з самага пачатку. Гэта мяркуе, што ваш уласны код атамны. Вы не можаце запісваць прамежкавыя вынікі ў агульны статус. Вы павінны альбо быць цалкам паспяховым, альбо цалкам праваліцца (як калі б вы не выконвалі ніякіх аперацый).

адказ 2:

Дзве зусім розныя рэчы. Thread-safe азначае функцыю, напісаную такім чынам, што яе можна выклікаць некалькі разоў шматлікімі тэмамі, без кожнай ніткі, якая перашкаджае функцыі іншай ніткі (напрыклад, змяняючы значэнне, калі адна зменная мяняецца на іншую Нітка выкарыстоўваецца).

Атамная азначае (калі я ведаю, куды вы ідзеце з ёй), што будзе створаны асобнік аб'екта. Незалежна ад таго, як часта на яго спасылаюцца, гэты асобнік (з любой тэмы) заўсёды адлюстроўваецца.


адказ 3:

Атамныя аперацыі - гэта спосаб дасягнуць бяспекі нітак, выкарыстоўваючы тып блакавання, напрыклад, мютэксы або семафоры, якія выкарыстоўваюць унутраныя атамныя аперацыі, альбо ажыццяўляючы без блакавання сінхранізацыю з выкарыстаннем атамных і захоўвання агародж.

Таму атамныя аперацыі на прымітыўных тыпах дадзеных з'яўляюцца інструментам для забеспячэння бяспекі нітак, але не гарантуюць аўтаматычную бяспеку нітак, паколькі вы звычайна выконваеце некалькі аперацый, якія залежаць адзін ад аднаго. Вы павінны пераканацца, што гэтыя аперацыі выконваюцца пастаянна, напрыклад, Б. з мютэксамі.

Так, напісанне аднаго з гэтых тыпаў атамных дадзеных у C # з'яўляецца бяспечным для тэмы, але гэта не робіць функцыю, якую вы выкарыстоўваеце ў тэме, бяспечнай. Гэта толькі гарантуе, што асобная аперацыя запісу выканана правільна, нават калі другая нітка звяртаецца да яе "адначасова". Тым не менш, пры наступным чытанні з бягучай ніткі не будзе забяспечана захаванне раней запісанага значэння, бо іншая нітка можа быць напісана на ім, але толькі тое, што значэнне чытання з'яўляецца сапраўдным.