【问题标题】:If the main thread holds a critical section, will a function attempting to acquire the critical section block if it's also on the main thread?如果主线程拥有一个临界区,如果它也在主线程上,尝试获取临界区的函数是否会阻塞?
【发布时间】:2017-09-29 19:10:41
【问题描述】:

我有点迷失在我正在分析的多线程应用程序中。我认为我试图理解的函数在主线程中起作用。确保我在其中放置了进入和退出临界区代码。同样的临界区也用于程序启动(进入临界区)和终止(离开临界区)。

如果我错了,请纠正我。如果我的函数在主线程中起作用,则应允许进入临界区。但事实并非如此 - 我的功能只是在进入关键部分时停止。根据我的理解,这个函数在另一个线程中起作用。

我的方法对于理解哪个函数在哪个线程中起作用是否正确?

【问题讨论】:

  • 你说得对,但是日志记录更简单,信息量更大。
  • 要检查您的代码是否在主线程中执行,请使用:Windows.GetCurrentThreadId() = System.MainThreadID。见What is function in Delphi to get the current executing thread?
  • 1) 为什么将整个程序放在临界区中? 2) 为什么您不接受您之前问题的答案?
  • @devundef 我知道为什么我的一些问题不被接受。通常我按接受勾号,它会变成绿色,但在我的活动日志中,只有一些问题被标记为已接受。

标签: multithreading delphi


【解决方案1】:

只需使用调试器。在应用程序的启动代码或应用程序的任何消息处理程序中设置断点,并在调试器线程窗口中检查当前线程 ID。然后在相关函数中设置断点,并在执行到该函数时检查线程 ID。如果它们不匹配,则该函数不会在运行 UI 消息的同一线程上调用。

当您在调试器中的函数中停止时,您可以查看调用堆栈窗口以查看导致您的函数调用的调用序列。这可以让您深入了解您是如何到达那里的,以及您是如何在不同的线程上到达那里的。

【讨论】:

    【解决方案2】:

    我相信您以错误的方式使用关键部分。 想象一下,您有一个可能在主线程和其他线程中修改的变量。每次要访问这个变量,你先Acquire临界区;像这样:

    if MyCriticalSection.TryEnter then  // MyVariable is accessible
    begin
      MyVariable := MyVariable + 1;
      MyCriticalSection.Release;
    end
    else begin
      // do something useful and try again in a few milliseconds.
    end;
    

    请记住,当您调用Acquire 时,调用线程将被冻结,直到临界区可用。因此,如果您在应用程序的开头调用 Acquire,第二次调用它会冻结您的主线程。

    【讨论】:

      【解决方案3】:

      您不能将其锁定在主线程中。始终在线程中使用临界区。将 cs:TRTLCriticalSection 声明为全局变量。调用任何线程。在不在主线程中或不在线程中的创建构造函数中的执行过程中锁定和解锁 cs。

      你也不能在主线程中读取 cnt 变量。但是 Synchronize 方法会更新 mainCnt 变量以便在主线程中读取它

      var //global
        cs :TRTLCriticalSection;
        cnt:integer;  //use it only inside thread
        mainCnt:integer; //same value for cnt. use it inside a main thread.
      
      ///formcreate..
      begin
        InitializeCriticalSection(cs);
      
      ///formdestroy
        DeleteCriticalSection(cs);
      
      type
        TThrInc = class(TThread)
        private
          fAnyParam:Integer;
        protected
          procedure Execute; override;
        public
          constructor Create(anyparam:integer);
        end;
      
      
      constructor TThrInc.Create(anyparam:integer);
      begin
        fAnyParam:=AnyParam;  //you dont need this
      end;
      
      procedure TThrInc.execute;
      var tmpcnt:integer;
      begin
        EnterCriticalSection(cs);
        try begin
          inc(cnt);
          tmpcnt:=cnt;
        end except end;
        LeaveCriticalSection(cs);
      
        Synchronize(
          procedure
          begin
            mainCnt:=tmpcnt;
          end);
      end;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-05
        • 2016-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多