Sobes.tech
Middle+

Ինչպե՞ս է կատարվում աշխատանքը հոսքերի և առաջադրանքների հետ C#-ում, երբ մի քանի հոսքեր են դիմում ընդհանուր վիճակի՞ն։

sobes.tech AI

Պատասխան AI-ից

Երբ աշխատում եք ընդհանուր վիճակի հետ մի քանի հոսքերում C#-ում, առաջանում են սինխրոնիզացիայի խնդիրներ և հնարավոր մրցակցության պայմաններ: Օգտագործվող մեխանիզմներն են՝

  1. Ապակողմնորոշում (Locking):

    • Օգտագործվում է lock օպերատորը՝ ստեղծելու համար քննադատական հատված, որը երաշխավորում է, որ միայն մեկ հոսք կարող է միաժամանակ մուտք ունենալ պաշտպանված ռեսուրս:
    // Օրինակ `lock`-ի օգտագործում
    private readonly object _lockObject = new object();
    private int _sharedCounter = 0;
    
    public void IncrementCounter()
    {
        lock (_lockObject)
        {
            _sharedCounter++; // Քննադատական հատված
        }
    }
    
  2. Ատոմիկ օպերացիաներ:

    • System.Threading.Interlocked դասը ապահովում է ատոմիկ օպերացիաներ (օրինակ, Increment, Decrement, Add, Exchange), որոնք հոսքային անվտանգ են և չեն պահանջում բացահայտ ապակողմնորոշում:
    // Օրինակ `Interlocked`-ի օգտագործում
    private volatile int _sharedValue = 0; // volatile փոփոխականների տեսանելիության համար
    
    public void UpdateValue(int newValue)
    {
        Interlocked.Exchange(ref _sharedValue, newValue); // Ատոմիկ նշանակում
    }
    
    public void IncrementValue()
    {
        Interlocked.Increment(ref _sharedValue); // Ատոմիկ ավելացում
    }
    
    • Թեև volatile ապահովում է փոփոխությունների տեսանելիությունը հոսքերում, այն չի երաշխավորում բազմաքայլային օպերացիաների ատոմիկությունը: Ատոմիկ օպերացիաների համար օգտագործեք Interlocked-ը:
  3. Սինխրոնիզացիայի դասեր System.Threading և System.Threading.Tasks-ից:

    • Monitor: ցածր մակարդակի սինխրոնիզացիայի մեխանիզմ՝ համեմատ lock-ի:
    • Mutex: թույլ է տալիս սինխրոնիզացնել մուտքը ռեսուրսին մի քանի պրոցեսների միջև:
    • SemaphoreSlim: սահմանափակում է միաժամանակ ռեսուրսին մուտք գործող հոսքերի քանակը:
    • ReaderWriterLockSlim: թույլ է տալիս միաժամանակ ընթերցել ռեսուրսը մի քանի հոսքերում, բայց միայն մեկին գրել:
  4. Հոսքային անվտանգ հավաքածուներ:

    • System.Collections.Concurrent տարածքը պարունակում է հավաքածուներ (ConcurrentBag<T>, ConcurrentDictionary<TKey, TValue>, ConcurrentQueue<T>, ConcurrentStack<T>), որոնք հատուկ նախագծված են բազմահոսքային օգտագործման համար: Այս հավաքածուների օգտագործումը վերացնում է անհրաժեշտությունը ձեռքով սինխրոնիզացիայի՝ հիմնական օպերացիաներում:
    // Օրինակ `ConcurrentDictionary`-ի օգտագործում
    private ConcurrentDictionary<string, int> _sharedData = new ConcurrentDictionary<string, int>();
    
    public void AddOrUpdateData(string key, int value)
    {
        _sharedData.AddOrUpdate(key, value, (k, oldValue) => oldValue + value);
    }
    
  5. Անփոփոխ օբյեկտներ (Immutable objects):

    • Անփոփոխ օբյեկտների ստեղծումը նշանակում է, որ նրանց վիճակը փոփոխել հնարավոր չէ ստեղծելուց հետո: Եթե ընդհանուր վիճակը ներկայացված է անփոփոխ օբյեկտով, ապա մի քանի հոսք կարող է անվտանգ ընթերցել այն առանց սինխրոնիզացիայի: Վիճակի թարմացումը կատարվում է նոր օրինակ ստեղծելով:

Տեղեկատվության ընդհանուր վիճակին մուտք գործելիս՝ Task-ների (Task Parallel Library) հետ աշխատելիս, նույնպես անհրաժեշտ է հաշվի առնել սինխրոնիզացիան: TPL-ն հեշտացնում է պարալելային գործողությունների ստեղծումը և կառավարումը, բայց չի հեռացնում ընդհանուր տվյալների անվտանգ աշխատելու պատասխանատվությունը:

Ընտրությունը համապատասխան սինխրոնիզացիոն մեխանիզմի կախված է կոնկրետ առաջադրանքից և ընդհանուր վիճակի մուտքի բնութագրերից։