Как работает semaphoreslim в c#?

Изучаю работу с потоками в c#. Сделал небольшой пример на WinForms для себя.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Windows.Forms;

namespace threadsLessons
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            Thread t1 = new Thread(() =>
            {
                M(label1);
            });
            t1.Start();

            new Thread(() => 
            {
                M(label2);
            }).Start();

            new Thread(() =>
            {
                M(label3);
            }).Start();

            new Thread(() =>
            {
                M(label4);
            }).Start();

            new Thread(() =>
            {
                M(label5);
            }).Start();

            new Thread(() =>
            {
                M(label6);
            }).Start();

        }

        void M(Label label)
        {
            SemaphoreSlim s = new SemaphoreSlim(1);

            s.Wait();
            for (int i = 0; i < 10; i++)
            {
               label.Text = i.ToString();
               Task.Delay(1000).Wait();
            }
            s.Release();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

    }
}

Мое непонимание заключается в том, что обновляются сразу 6 label'ов. Хотя вроде как принимается только 1 поток одновременно. Вроде сам по себе Semaphore работает, но работает почему то больше потоков. Может я что то сделал не так или неправильно понимаю работу семафора?


Ответы (1 шт):

Автор решения: aepot

Просто приведу этот код к рабочему виду. Проблема не в семафоре, а в том как вы код написали с ошибками. Семафор должен быть один на все задачи. Разные семафоры никак не зависят друг от друга, здесь нет никакой магии.

Чтобы не мудрить с потоками, использую async/await.

private async void button1_Click_1(object sender, EventArgs e)
{
    try
    {
        using SemaphoreSlim semaphore = new SemaphoreSlim(1);
        Label[] labels = new[] { label1, label2, label3, label4, label5, label6 };
        List<Task> tasks = new List<Task>();

        foreach (Label label in labels)
        {
            tasks.Add(() => M(label, semaphore));
        }

        await Task.WhenAll(tasks);
        MessageBox.Show("Готово");
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

async Task M(Label label, Semaphore semaphore)
{
    await semaphore.WaitAsync();
    try
    {
        for (int i = 0; i < 10; i++)
        {
            label.Text = i.ToString();
            await Task.Delay(1000);
        }
    }
    finally
    {
        semaphore.Release();
    }
}

Почитать еще:

→ Ссылка