#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
, подразумевается… хотя мы также не можем сделать вывод, что это не так; p2. @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
(если только он никогда не возвращается).