Использование Мьютекса в c#

#c# #multithreading #mutex

#c# #многопоточность #мьютекс

Вопрос:

Я немного новичок в потоковой обработке в C # и вообще, в своей программе я использую mutex , чтобы разрешить только 1 потоку попадать внутрь критической секции, и по неизвестной причине, выполнив несколько cw-отпечатков, я вижу, что более 1 потока попадает внутрь моей критической секции, и это мой код :

 Mutex m = new Mutex();
m.WaitOne();
<C.S> // critical section here
m.ReleaseMutex();
  

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

Редактировать:

Мой код включает классы, поэтому в основном он выглядит примерно так:

 public class test
{
    private mutex m;
    public test()
    {
         m = new mutex();
    }
    public func()
    {
         m.WaitOne();
         <C.S> // critical section here
         m.ReleaseMutex();
     }


    } 
  

Комментарии:

1. У вас должно быть более одного экземпляра класса.

2. Это мьютекс на уровне экземпляра; вы уверены, что ваш код не находится в критической секции для отдельных несвязанных экземпляров? Кроме того, любая ошибка приведет к постоянной блокировке кода — для обеспечения безопасности вам нужен try / finally .

3. После редактирования: этот мьютекс работает только на уровне объекта, т.Е. 1 CrticialSection / instance. Это то, чего ты хочешь?

4. Информация: Mutex является mutual exclusion

Ответ №1:

Проблема здесь в том, что все ваши вызывающие устройства используют разные мьютексы; вам нужно, чтобы объект блокировки был общим, обычно путем преобразования его в поле. Например, и переключение на более простую lock метафору:

 private readonly object syncLock = new object();
public void ThreadSafeMethod() {
    lock(syncLock) {
        /* critical code */
    }
}
  

или использование мьютекса:

 private readonly Mutex m = new Mutex();
public void ThreadSafeMethod() {
    m.WaitOne();
    try {
        /* critical code */
    } finally {
        m.ReleaseMutex();
    }
}
  

Комментарии:

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

2. @Nadav — это не то, что показывает ваш вопрос … ваш вопрос показывает это как то же местоположение, что и код, то есть локальную переменную.

3. Nadav — вы уверены, что у вас нет более одного экземпляра класса? Почти все проблемы «блокировка / мьютекс пропускает несколько вызовов» оказываются в том, что объектов блокировки / мьютекса больше, чем вы предполагали.

Ответ №2:

Похоже, что вы предоставляете каждому потоку свой собственный мьютекс. Это не сработает.

А Мьютекс в большинстве ситуаций излишен. Вам нужно только:

 private static object syncLock = new object();  // just 1 instance

....

lock(syncLock)
{
    // critical section
}
  

Комментарии:

1. Я не уверен, что из вопроса, который мы можем вывести static , подразумевается… хотя мы также не можем сделать вывод, что это не так; p

2. @Marc, правильно. Я использовал static как противоположность тому, что я считаю ошибкой. Код не совсем понятен.

Ответ №3:

Этот шаблон вообще не блокирует. Каждый поток создает новый объект Мьютекса и немедленно становится владельцем блокировки для него. Другие потоки сами создают и используют новый мьютекс.

Рассмотрите возможность использования обычной lock()!

 lock(_lockobject) {
   // do inside what needs to be done - executed on a single thread only
} 
  

где _lockobject — это простая частная переменная в вашем классе:

 private object _lockobject; 
  

Редактировать: спасибо комментаторам! Существуют ситуации, когда блокировка (this) может быть опасной. Итак, я удалил это.

Комментарии:

1. Не lock(this) , или lock(someType) , или lock(anyString) — это плохие проекты и они ненадежны.

2. Кстати, блокировать это не всегда хорошая идея, лучше создать простую переменную типа object toolazy.me.uk /…

3. блокировка (это) не считается хорошей практикой. (Смотрите, например haacked.com/archive/2006/08/08/ThreadingNeverLockThisRedux.aspx ). Гораздо лучше создать объект только для блокировки и забыть, что . Ошибка сетевого проектирования, которая позволяет блокировать любой объект, когда-либо допускалась.

4. @WillDean — действительно; я бы предпочел, чтобы существовал определенный тип, например Monitor экземпляры. Также object должно быть abstract ;p

Ответ №4:

Мьютекс используется для идентификации запущенного экземпляра приложения.

  using (Mutex mutex = new Mutex(true, "app name", out createdNew))
            {
                if (createdNew)//check app is already run
                {
                    KillOthers();
                    StartApp();
                }
                else
                {
                    MessageBox.Show("Another instance already running!");
                }
            }
  

Ответ №5:

Могу ли я добавить исправление к принятому ответу?

 private readonly Mutex m = new Mutex();
public void ThreadSafeMethod() {
    while(!m.WaitOne()){}
    try {
        /* critical code */
    } finally {
        m.ReleaseMutex();
    }
}
  

Комментарии:

1. Привет, Эмануэле. Почему вы думаете, что ваш ответ является улучшением? Цикл: while (!m.WaitOne()) { } никогда не будет выполняться более одного раза, потому что WaitOne метод без аргументов всегда возвращает true (если только он никогда не возвращается).