Шаг 103 - Mutex

В "Шаг 84 - Критическая секция" Артём рассказал про критические секции, хочу некоторые моменты про критические секции и добавить кое-что про мьютексы. Там создавалась критическая секция в которой блокировалась переменная sync.

class MainClass
{
	public static Object sync = "var lock";
		...
	public static void Proc1() 
	{
		lock(sync)
		{
			...
		}
	}
}

Но она имела тип object. Всё конечно хорошо, но что бы мы делали если бы она имела тип int или просто нужно было бы, что - то синхронизировать в статическом методе. Для этого нужно было бы залочить следующим образом lock(typeof(MainClass)) По идее lock имеет следующий вид lock(expression), где expression экземпляр объекта, причём он должен быть, как я понял ссылочного типа(класс, интерфейс, делегат и т.д.) Значения типа int и т.д. тут не катят. Но если мы хотим защитить статическую переменную или критическая секция находится в static методе, то expression будет иметь вид typeof(class).

Теперь перейдём к мьютексам. Аналогом мьтексов в .Net является класс Mutex. Три конструктора позволяют создать объект мьютекс

Mutex();
Mutex(bool initiallyOwned);
Mutex(bool initiallyOwned, string name);

Пример

Mutex mutex  = new Mutex(false, "testmutex");

Первый конструктор я думаю объяснять не надо, второй конструктор создаёт мьютекс, если initiallyOwned равна trueWaitOne и ReleaseMutex, первый метод:

public virtual bool WaitOne();
public virtual bool WaitOne(TimeSpan, bool);
public virtual bool WaitOne(int , bool);

Первый ждёт неопределенно долгое время, второй и третий метод будут ждать в течении некоторого промежутка времени выраженного TimeSpan или int. Также есть методы WaitAny и WaitAll

public static bool WaitAll(WaitHandle[]);
public static bool WaitAll(WaitHandle[], int,  bool);
public static bool WaitAll(WaitHandle[], TimeSpan,  bool);
public static int WaitAny(WaitHandle[]);
public static int WaitAny (WaitHandle[], int,  bool);
public static int WaitAny (WaitHandle[], TimeSpan,  bool);

Метод WaitAny ждёт освобождения любого объекта из массива WaitHandle, а WaitAll всех. Класс WaitHandle является предком мьютексов, потоков, событий, процессов, AppDomain и т.д., так что в этот массив можно запихивать разные объекты, одновременно там может быть и событие и мьютекс. Функция ReleaseMutex() уменьшает счётчик мьютекса на единицу. Пример создания мьютекса и его использование.

Mutex mutex = new Mutex(false, "testmutext);
mutex.WaitOnce();
someproc();
.....
mutex.ReleaseMutex();

Есть ещё два интересных метода SetHandle и int GetHandle()

SetHandle(int handle)
int GetHandle()

Первый устанавливает native handle("родной указатель для операционки" не могу подобрать аналог в русском), тот который мы получаем при вызове API функции CreateMutex второй служит, чтобы получить хандл, который используется мьютексом. Далее приводится небольшой пример, создаются два листбокса и 4 потока, в первых двух для синхронизации используются критические секции, во вторых двух мьютексы. И каждый поток добавляет в листбокс строку. Интересный результат получается при запуске нескольких приложений, критические секции как работали так и будет работать, а вот с мьютексами другое дело. Чем больше приложений тем более, медленней будут добавлятся строки там где используются мьютексы, так как у нас создаются "именованные" мьютексы(как известно мьютексы используются для синхронизации приложений). Странная вещь почему - то они обрабатыватся странным способом, сперва два мьютекса в одном приложении, потом два в другом и т.д., я всё таки надеялся, они будут добавляться не по два одновременно за раз(вроде как мьютексы стоят в очереди FIFO). Странная вещь ещё наблюдалась если в API функциях при создании потоков можно было, передавать при старте Thread какое-то значение, то здесь нет. В делегате ThreadStart нет передаваемых значений. Приходилось создавать для каждого потока класс, обидно конечно. В примере закоментированы строки для сихронизации по static переменной

//	 static int LockVariable = 0;
...
lock(form.CriticalSection)//typeof(MyThreadFunction)

В первой строке уберите //, а во второй вместо Form.CriticalSection вставьте typeof(MyThreadFunction).


Загрузить проект | Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Leonid Molochniy - 15.10.2001