Как определить находится ли поток в критической секции?

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by Redeemer, 3 Sep 2010.

  1. Redeemer

    Redeemer Member

    Joined:
    3 Jul 2010
    Messages:
    203
    Likes Received:
    24
    Reputations:
    1
    Как определить находится ли поток в критической секции из самого этого потока?
    То есть мне нужно знать выполняется ли текущий код в пределах критической секции или нет.
    Возможно ли это вообще?
     
    #1 Redeemer, 3 Sep 2010
    Last edited: 3 Sep 2010
  2. Irdis

    Irdis Elder - Старейшина

    Joined:
    6 Feb 2006
    Messages:
    248
    Likes Received:
    52
    Reputations:
    3
    Поставить брейк поинт в критическую секцию. Или принтить id(или name) потока в Output, при входе в критическую секцию.
    Вариантов много.
     
  3. Redeemer

    Redeemer Member

    Joined:
    3 Jul 2010
    Messages:
    203
    Likes Received:
    24
    Reputations:
    1
    Мне нужно это сделать из этого самого потока, причем желательно без использования сторонних ресурсов.
    Ключеваяособенность: Этот код будет исполняться в классе-предке, поэтому он не знает поместил ли наследник этот вызов в критическую секцию или нет. И по этому же он не может при входе в секцию поставить никакую пометку.
     
  4. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Судя по объявлению критической секции в дельфи могу предположить что OwningThread - хэндл потока находящегося внутри секции, LockCount - количество залоченных потоков, а RecursionCount - количество локов текущим потоком
    Уточни в мсдн
     
  5. Redeemer

    Redeemer Member

    Joined:
    3 Jul 2010
    Messages:
    203
    Likes Received:
    24
    Reputations:
    1
    GhostOnline, спасибо, покурю MSDN на эту тему. Но проблема в том, что критическая секция создается в наследнике, и предок о ней просто не знает. Соответственно получить ссылку на _RTL_CRITICAL_SECTION тоже не может.

    Задолбался уже, весь мозг сломал
     
  6. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    А предок тоже твой класс что-ли?
     
  7. Redeemer

    Redeemer Member

    Joined:
    3 Jul 2010
    Messages:
    203
    Likes Received:
    24
    Reputations:
    1
    Тоже мой, оба класса мои
     
  8. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Ну заведи в предке абстрактный метод определяющий находится ли поток в КС и возвращающий булевый тип, а в наследнике переопредели его. Тогда в предке можно вызывать его не открывая крит. секцию, делов-то
     
  9. Redeemer

    Redeemer Member

    Joined:
    3 Jul 2010
    Messages:
    203
    Likes Received:
    24
    Reputations:
    1
    Я думал над этим. В принципе я могу поступить еще проще - добавить в ThreadInfo еще одно поле.
    Но я надеялся что есть способ определения вообще без пометок. дебаг-апишка какая или еще что подобное
     
  10. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    937
    Likes Received:
    162
    Reputations:
    27
    Зачем так сложно?
    Судя по задачи, мы можем просто на вход в критическую секцию присвоить некоторому значению Flag значение True, при выходе - False. Если Flag равняется True, - значит поток в критической секции, иначе, - нет.
    Вот тебе и все решение твоей задачи...
     
  11. Bers

    Bers Member

    Joined:
    17 May 2010
    Messages:
    78
    Likes Received:
    30
    Reputations:
    26
    Не выйдет. Возникнет race condition по этой переменной.
    Лучше попробовать такое решение (напишу псевдокодом, ок? :) )
    Code:
    
    // идентификатор критической секции
    critical_section cs;
    
    ....
    
    // Здесь какой-то код, работающий с этой критической секцией
    void Foo()
    {
      enter_critical_section(&cs);
      // do smth
      leave_critical_section(&cs);  
    }
    
    
    // А здесь - наш код, проверяющий, 
    // занята или свободна ли сейчас критическая секция
    void Bar()
    {
      bool result = try_enter_critical_section(&cs);
      if(!result)
      {
        // В критической секции находится какой-то поток.
      } else
      {
        // Критическая секция была свободна
        // теперь она занята нашим потоком.
        leave_critical_section(&cs);
      }
    }
    

    UPD: Пардон, проглядел вот это:

    В этом случае ответ простой - пересмотреть архитектуру. Если классу-предку необходимо знать, находится ли данный вызов в критической секции или нет - значит, класс-наследник должен ему эту информацию предоставить:
    Code:
    class BaseClass
    {
       protected:
         void Foo()
         {
           if(IsInCriticalSection())
             printf("In a critical section\n");
           else
             prinft("Not in a critical section\n");
         }
    
      virtual bool IsInCriticalSection() = 0;
    }
    
    class DerivedClass : BaseClass
    {
      public void Bar()
      {
        EnterCriticalSection();
        
        // Вызов в критической секции
        Foo();
    
        LeaveCriticalSection();
    
    
        // Вызов вне критической секции
        Foo();
      }
    
      protected:
        virtual bool IsInCriticalSection()
        {
          return mutexSstate;
        }
    
      private:
        void EnterCriticalSection()
        {
           ASSERT(mutexSstate== false);
           mutex->enter();
           mutexSstate= true;
        }
    
        void LeaveCriticalSection()
        {
           ASSERT(mutexSstate== true);
           mutex->leave();
           mutexSstate= false;
        }
    
        CMutex* mutex;
        bool mutexSstate = false;
    }
    
    
     
    #11 Bers, 3 Sep 2010
    Last edited: 3 Sep 2010
    1 person likes this.
  12. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    937
    Likes Received:
    162
    Reputations:
    27
    Ничего такого не возникнет, если переменная будет локальной для каждого потока, а не глобальной.
     
    #12 Chrome~, 3 Sep 2010
    Last edited: 3 Sep 2010
  13. Bers

    Bers Member

    Joined:
    17 May 2010
    Messages:
    78
    Likes Received:
    30
    Reputations:
    26
    Согласен. Я пропустил пост топикстартера, где он уточнял, что его интересует состояние текущего потока. Из первого поста я решил, что его интересует состояние другого потока.
    Свой ответ я отредактировал :)

    Хотя если такизх вызовов функции может быть несколько одновременно, из разных потоков - эту переменную придется делать thread local.
     
  14. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Ну вы ребята даете
    Прочитай пост №8, это решение уже предлагалось.
    Такое решение - первое что приходит в голову обычно.
    Этим самым эта переменную надо делать глобальной, а ТС же юзает только поля класса как я понял. Т.е. предок ничего не должен знать о наследнике и его крит. секциях, инкапсуляция какбэ.
     
  15. Redeemer

    Redeemer Member

    Joined:
    3 Jul 2010
    Messages:
    203
    Likes Received:
    24
    Reputations:
    1
    Немного поясню для чего мне это надо:
    У предка есть функция GetData, которая пытается получиль значение из некоего источника. При этом в источнике может не быть данных, тогда функция усыпляет текущий поток, то есть фактически вызывающй поток засыпает и остается внутри функции. Затем его можно разбудить (это уже другая история) и он продолжит попытки чтения из источника.
    Наследники обычно вызывают GetData напрямую и проблем не возникает. Однако однажды мне пришлось сделать вызов из критической секции. При этом если в источнике данных нет, то поток засыпает. А поскольку он находится в критической секции, то все остальные потоки тормозят на входе в нее.
    Поэтому мне нужно внутри GetData как-то узнавать находится ли этот вызов внутри критической секции, чтобы не усыплять поток
     
    #15 Redeemer, 4 Sep 2010
    Last edited: 4 Sep 2010
  16. Irdis

    Irdis Elder - Старейшина

    Joined:
    6 Feb 2006
    Messages:
    248
    Likes Received:
    52
    Reputations:
    3
    Усыплять поток надо так, что бы он ждал прихода данных в критической секции при этом не блокируя её. Если так то...
    Code:
    using System;
    using System.Diagnostics;
    using System.Threading;
    using System.Collections;
    
    namespace MonitorCS1
    {
        class MonitorSample
        {
            private bool isDataRecived = false;
    
            public void FirstThread()
            {
                GetData();
            }
            public void SecondThread()
            {
                GetData();
            }
            public void GetData()
            {
                lock (this)
                {
                    //try recive data
                    //...
                    //...
                    if (!isDataRecived)
                    {
                        isDataRecived = true; //предположим что Data получена когда мы зайдём в метод второй раз
                        Monitor.Wait(this); //отдаём обект синхронизации, 
                                            //поток ждёт Pulse не блокируя вход  в критическую секцию
                    }
                    else
                    {
                        Monitor.PulseAll(this); // говорим всем потокам которые ждут, что дата получена
                    }
                    // read data
                } 
            }
    
            static void Main(string[] args)
            {
                MonitorSample test = new MonitorSample();
                Thread tFirst = new Thread(test.FirstThread);
                Thread tSecond = new Thread(test.SecondThread);
                tFirst.Start();
                tSecond.Start();
                test.GetData();
                tFirst.Join();
                tSecond.Join();
            }
        }
    }
    
     
    #16 Irdis, 4 Sep 2010
    Last edited: 4 Sep 2010