草庐IT

c++ - QTimer对象是否在单独的线程中运行?其作用机理是什么?

coder 2023-05-03 原文

When I create a QTimer object in Qt 5, and start it using the start() member function, is a separate thread created that keeps track of the time and calls the timeout() function at regular intervals?



例如,
QTimer *timer = new QTimer;
timer->start(10);
connect(timer,SIGNAL(timeout()),someObject,SLOT(someFunction()));

在这里,程序如何知道timeout()何时发生?我认为它必须在单独的线程中运行,因为我看不到顺序程序如何跟踪时间并同时继续执行。但是,我无法在Qt文档或其他任何地方找到与此相关的任何信息来确认这一点。

我已经阅读了the official documentation,关于StackOverflow的某些问题(例如thisthis)似乎很相关,但是我无法通过它们得到答案。

谁能解释QTimer对象工作的机制?

在进一步搜索时,我发现按照this answerBill所述,

Events are delivered asynchronously by the OS, which is why it appears that there's something else going on. There is, but not in your program.



这是否意味着timeout()由操作系统处理?是否有一些硬件可以跟踪时间并以适当的时间间隔发送中断?但是,如果是这种情况,那么由于许多计时器可以同时独立运行,那么如何分别跟踪每个计时器?

机制是什么?

谢谢你。

最佳答案

When I create a QTimer object in Qt 5, and start it using the start() member function, is a separate thread created that keeps track of the time and calls the timeout() function at regular intervals?



不;创建一个单独的线程将很昂贵,并且没有必要,因此这不是实现QTimer的方式。

Here, how does the program know when timeout() occurs?



QTimer::start()方法可以调用系统时间函数(例如gettimeofday()或类似的函数)以找出(在几毫秒内)调用start()的时间。然后,它可以在该时间上加上十毫秒(或您指定的任何值),现在它具有一条记录,指示何时应该下一次发出timeout()信号。

因此,有了这些信息,它将如何确保这种情况发生?

要知道的关键事实是,仅当/当您的Qt程序在Qt的事件循环内执行时,QTimer超时信号发射才起作用。几乎每个Qt程序都会有类似这样的内容,通常在其main()函数的底部附近:
QApplication app(argc, argv);
[...]
app.exec();

注意,在一个典型的应用程序中,几乎所有应用程序的时间都将花费在exec()调用中。也就是说,直到退出应用程序时,app.exec()调用才会返回。

那么,在您的程序运行时,exec()调用内部发生了什么?对于像Qt这样的大型复杂库,它一定很复杂,但是说它正在运行一个事件循环,从概念上看,这并不是一件简单的事:
 while(1)
 {
     SleepUntilThereIsSomethingToDo();  // not a real function name!
     DoTheThingsThatNeedDoingNow();     // this is also a name I made up
     if (timeToQuit) break;
 }

因此,当您的应用处于空闲状态时,该过程将在SleepUntilThereIsSomethingToDo()调用中进入休眠状态,但是一旦事件需要处理(例如,用户移动鼠标,按下键或数据到达套接字)等等),SleepUntilThereIsSomethingToDo()将返回,然后将执行响应该事件的代码,从而导致相应的操作,例如小部件更新或调用timeout()信号。

那么,SleepUntilThereIsSomethingToDo()如何知道何时该醒来并返回?这将取决于您所运行的操作系统而有很大不同,因为不同的操作系统具有不同的API来处理这种事情,但是实现此类功能的经典UNIX-y方法是使用POSIX select()调用:
int select(int nfds, 
           fd_set *readfds, 
           fd_set *writefds,
           fd_set *exceptfds, 
           struct timeval *timeout);

请注意,select()接受三个不同的fd_set参数,每个参数都可以指定许多文件描述符。通过将适当的fd_set对象传递给那些参数,您可以使select()能够在您要监视的一组文件描述符中的任何一个上进行I/O操作时立即唤醒,以便您的程序可以处理I/O没有延迟。但是,对我们来说有趣的部分是最后一个参数,它是一个超时参数。特别是,您可以在此处传递一个对select()说的struct timeval对象:“如果在(这么多)微秒后未发生任何I/O事件,那么您就应该放弃并返回”。

事实证明这非常有用,因为通过使用该参数,SleepUntilThereIsSomethingToDo()函数可以执行以下操作(伪代码):
void SleepUntilThereIsSomethingToDo()
{
   struct timeval now = gettimeofday();  // get the current time
   struct timeval nextQTimerTime = [...];  // time at which we want to emit a timeout() signal, as was calculated earlier inside QTimer::start()
   struct timeval maxSleepTimeInterval = (nextQTimerTime-now);
   select([...], &maxSleepTimeInterval);  // sleep until the appointed time (or until I/O arrives, whichever comes first)
}

void DoTheThingsThatNeedDoingNow()
{
   // Is it time to emit the timeout() signal yet?
   struct timeval now = gettimeofday();
   if (now >= nextQTimerTime) emit timeout();

   [... do any other stuff that might need doing as well ...]
}   

希望这是有道理的,您可以看到事件循环如何使用select()的timeout参数来使其唤醒,并在(大约)调用start()之前计算出的时间发出timeout()信号。 )。

顺便说一句,如果该应用程序同时激活了多个QTimer,那没问题;在那种情况下,SleepUntilThereIsSomethingToDo()只需遍历所有 Activity 的QTimers即可找到具有最小下次超时时间戳的QTimer,并仅使用该最小时间戳来计算select()的最大时间间隔。应该被允许 sleep 。然后,在select()返回之后,DoTheThingsThatNeedDoingNow()也对 Activity 计时器进行迭代,并且仅针对其下一个超时时间戳不大于当前时间的计时器发出超时信号。重复事件循环(根据需要快速或慢速进行),以产生类似的多线程行为,而实际上并不需要多个线程。

关于c++ - QTimer对象是否在单独的线程中运行?其作用机理是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42279360/

有关c++ - QTimer对象是否在单独的线程中运行?其作用机理是什么?的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  3. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  4. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  5. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  6. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  7. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  8. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  9. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  10. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

随机推荐