Как я могу заблокировать один поток в C # - PullRequest
1 голос
/ 30 марта 2012

Я бы хотел "заблокировать" ресурс в одном потоке. Я перепробовал все запирающие механизмы, которые только мог придумать, но я не могу заставить это работать.

В приведенном ниже примере, когда срабатывает таймер, я не хочу, чтобы код в DoSomething выполнялся, пока не вернется ShowDialog. Я ожидал, что оператор блокировки разрешит возврат только одному экземпляру Form2, но на самом деле все это выполняется в одном потоке, поэтому он не мешает потоку повторно войти в этот блок кода.

Вот пример кода, это не точный сценарий, с которым я столкнулся, но он иллюстрирует проблему. В моем фактическом коде я получаю события от подключенного устройства, поэтому нет таймера.

Для воспроизведения создайте приложение Windows Forms и добавьте Form1 и Form2. Скопируйте этот код в Form1:

public partial class Form1 : Form
{
    Timer _timer = new Timer();
    private static object _lock = new object();

    public Form1()
    {
        InitializeComponent();

        _timer.Tick += delegate { DoSomething(); };
        _timer.Interval = 5000;
        _timer.Start();
    }

    private void DoSomething()
    {
        lock (_lock)
        {
            Form2 form2 = new Form2();
            form2.ShowDialog();
        }
    }
}

Ответы [ 3 ]

4 голосов
/ 30 марта 2012

Флаг должен сделать трюк, если вы используете ThreadStaticAttribute.

public partial class Form1 : Form
{
    Timer _timer = new Timer();
    [ThreadStatic]
    bool inEvent = false;

    public Form1()
    {
        InitializeComponent();

        _timer.Tick += delegate { DoSomething(); };
        _timer.Interval = 5000;
        _timer.Start();
    }

    private void DoSomething()
    {
        // if you want to stay here and wait instead of exiting, you could do:
        // while (inEvent);
        if (!inEvent)
        {
            inEvent = true;
            Form2 form2 = new Form2();
            form2.ShowDialog();
            inEvent = false;
        }
    }
}
1 голос
/ 30 марта 2012

Шон, звучит так, будто другие не решают твою актуальную проблему. Похоже, вы представляете большую проблему в простом решении. В любом случае, блокировка не будет работать в том же потоке. Он предназначен для блокировки других потоков. Если в том же потоке обнаружена блокировка, он просто увеличивает счетчик ссылок или что-то в этом роде и позволяет входу блокировать только другие потоки, пока счетчик ссылок не станет равным нулю.

Итак, изначально я думал, что Mutex, Semaphore, SpinWait, SpinUntil помогут, но в то время как они будут в конечном итоге блокировать удовлетворение вашей потребности предотвратить вход, однако ваше приложение будет затем заблокировано и ожидает, потому что вы находитесь в потоке пользовательского интерфейса так что вы даже не сможете закрыть Form2 (или что-то еще, с чем вы работаете).

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

public partial class Form1 : Form
{
    Timer _timer = new Timer();
    private readonly static object _lock = new object();

    public Form1()
    {
        InitializeComponent();

        _timer.Tick += delegate { OnTimerTick(); };
        _timer.Interval = 5000;
        _timer.Start();
    }

    private void OnTimerTick()
    {
        new System.Threading.Thread (DoSomething).Start();
    }

    private void DoSomething()
    {
        Console.WriteLine("Before Lock");

        lock(_lock)
        {
            // Do stuff...

            Form2 form2 = new Form2();
            form2.ShowDialog();

        }

        Console.WriteLine("After Lock");
    }
}

Удачи. Если это помогло, не забудьте проголосовать за этот ответ.

Спасибо, Том

1 голос
/ 30 марта 2012

Не могли бы вы создать один экземпляр формы, сохранить его в переменной класса, а затем использовать проверку его свойства Visible?

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.visible.aspx

public partial class Form1 : Form
{
    Timer _timer = new Timer();
    Form2 form2 = new Form2();

    public Form1()
    {
        InitializeComponent();

        _timer.Tick += delegate { DoSomething(); };
        _timer.Interval = 5000;
        _timer.Start();
    }

    private void DoSomething()
    {
        if(!form2.Visible)
        {
           form2.ShowDialog();
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...