Как сделать мьютекс не рекурсивным

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

using System;
using System.Collections.Generic;
using System.Text;

using System.Threading;

namespace Test {
    class Program {
        static volatile Mutex mut1 = new Mutex();
        static volatile Mutex mut2 = new Mutex();
        static void Main(string[] args) {
            mut1.WaitOne(); Console.WriteLine("1W");
            mut2.WaitOne(); Console.WriteLine("2W");
            Thread oThread = new Thread(new ThreadStart(fn2));
            oThread.Start();
            mut1.WaitOne(); Console.WriteLine("1W");
            Console.WriteLine("Second");
            mut1.ReleaseMutex(); Console.WriteLine("1R");
        }
        static void fn2() {
            Console.WriteLine("First");
            mut2.ReleaseMutex(); Console.WriteLine("2R");
            mut1.ReleaseMutex(); Console.WriteLine("1R");
        }
    }
}

person Community    schedule 13.12.2009    source источник
comment
Рекурсивные мьютексы взаимоблокируются реже, чем нерекурсивные. Почему вы предпочитаете нерекурсивную версию? (Я имею в виду: если вы пишете свою программу так, чтобы она не блокировалась с нерекурсивной версией, она все равно будет работать с рекурсивной)   -  person Pascal Cuoq    schedule 13.12.2009
comment
Отсутствие ответа: я вспомнил, что critical sections были небольшой вариацией мьютексов, но, проверив, версия критических секций Windows также является рекурсивной.   -  person Pascal Cuoq    schedule 13.12.2009


Ответы (1)


Во-первых, я не уверен, что вы действительно понимаете мьютексы, вы можете освободить их только в контексте (т.е. потоке), в котором они были заблокированы с самого начала, поэтому использование их в качестве неких точек защиты не имеет большого смысла.

Возможно, имеет смысл использовать семафоры в этом кейс. Но вы все равно должны понять, что вы действительно пытаетесь сделать :)

using System;
using System.Collections.Generic;
using System.Text;

using System.Threading;

namespace Test
{
    class Program
    {
        static Semaphore sem1 = new Semaphore(1, 1);
        static Semaphore sem2 = new Semaphore(1, 1);
        static void Main(string[] args)
        {           
            sem1.WaitOne(); Console.WriteLine("1W");
            sem2.WaitOne(); Console.WriteLine("2W");
            Thread oThread = new Thread(new ThreadStart(fn2));
            oThread.Start();
            sem1.WaitOne(); Console.WriteLine("1W");
            Console.WriteLine("Second");
            sem1.Release(); Console.WriteLine("1R");
        }
        static void fn2()
        {
            Console.WriteLine("First");
            sem2.Release(); Console.WriteLine("2R");
            sem1.Release(); Console.WriteLine("1R");
        }
    }
}
person tyranid    schedule 13.12.2009