ImageVerifierCode 换一换
格式:DOC , 页数:18 ,大小:36.04KB ,
资源ID:8193209      下载积分:8 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/8193209.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(黑马程序员C语言教程Qt多线程程序设计.doc)为本站上传会员【精****】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

黑马程序员C语言教程Qt多线程程序设计.doc

1、传智播客C/C++培训教授: Qt多线程程序设计 分类: C/C++ QT通过三种形式提供了对线程的支持。它们分别是,一、平台无关的线程类,二、线程安全的事件投递,三、跨线程的信号-槽连接。这使得开发轻巧的多线程Qt程序更为轻易,并能充足利用多处理器机器的优势。多线程编程也是一个有用的模式,它用于处理执行较长时间的操作而不至于用户界面失去响应。在Qt的早期版本中,在构建库时有不选择线程支持的选项,从4.0开始,线程总是有效的。 线程类 Qt 包括下面某些线程有关的类: QThread 提供了开始一

2、个新线程的措施 QThreadStorage 提供逐线程数据存储 QMutex 提供相互排斥的锁,或互斥量 QMutexLocker 是一个便利类,它能够自动对QMutex加锁与解锁 QReadWriterLock 提供了一个能够同时读操作的锁 QReadLocker与QWriteLocker 是便利类,它自动对QReadWriteLock加锁与解锁 QSemaphore 提供了一个整型信号量,是互斥量的泛化 QWaitCondition 提供了一个措施,使得线程能够在被另外线程唤醒之前一直休眠。 创建一个线程 为创建一个线程,子类化QThread并且重

3、写它的run()函数,例如: class MyThread : public QThread { Q_OBJECT protected: void run(); }; void MyThread::run() { ... } 创建这个线程对象的实例,调用QThread::start()。于是,在run()里出现的代码将会在另外线程中被执行。 注意:QCoreApplication::exec()必须总是在根本程(执行main()的那个线程)中被调用,不能从一个QThread中调用。在GUI程序中,根本程也被称为GUI线程,因为它是唯一一个

4、允许执行GUI有关操作的线程。另外,你必须在创建一个QThread之前创建QApplication(or QCoreApplication)对象。   线程同时 QMutex, QReadWriteLock, QSemaphore, QWaitCondition 提供了线程同时的伎俩。使用线程的重要想法是希望它们能够尽也许并发执行,而某些核心点上线程之间需要停止或等候。例如,假如两个线程试图同时访问同一个全局变量,成果也许不如所愿。 QMutex 提供相互排斥的锁,或互斥量。在一个时刻至多一个线程拥有mutex,假如一个线程试图访问已经被锁定的mutex,那么它将休眠,直到

5、拥有mutex的线程对此mutex解锁。Mutexes常用来保护共享数据访问。 QReadWriterLock 与QMutex相同,除了它对 "read","write"访问进行区分看待。它使得多个读者能够共时访问数据。使用QReadWriteLock而不是QMutex,能够使得多线程程序更具备并发性。 QReadWriteLock lock; void ReaderThread::run() { // ... lock.lockForRead(); read_file(); lock.unlock(); //... }

6、 void WriterThread::run() { // ... lock.lockForWrite(); write_file(); lock.unlock(); // ... } QSemaphore 是QMutex的一般化,它能够保护一定数量的相同资源,与此相对,一个mutex只保护一个资源。下面例子中,使用QSemaphore来控制对环状缓冲的访问,此缓冲区被生产者线程和消费者线程共享。生产者不停向缓冲写入数据直到缓冲末端,再从头开始。消费者从缓冲不停读取数据。信号量比互斥量有愈加好的并发性,假如我们用互斥量来控制对缓冲

7、的访问,那么生产者,消费者不能同时访问缓冲。然而,我们懂得在同一时刻,不一样线程访问缓冲的不一样部分并没有什么危害。 const int DataSize = 100000; const int BufferSize = 8192; char buffer[BufferSize]; QSemaphore freeBytes(BufferSize); QSemaphore usedBytes; class Producer : public QThread { public: void run(); }; void Producer::run() {

8、 qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); for (int i = 0; i < DataSize; ++i) { freeBytes.acquire(); buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4]; usedBytes.release(); } } class Consumer : public QThread { public: void run(); }; voi

9、d Consumer::run() { for (int i = 0; i < DataSize; ++i) { usedBytes.acquire(); fprintf(stderr, "%c", buffer[i % BufferSize]); freeBytes.release(); } fprintf(stderr, "\n"); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv);

10、 Producer producer; Consumer consumer; producer.start(); consumer.start(); producer.wait(); consumer.wait(); return 0; } QWaitCondition 允许线程在某些情况发生时唤醒另外的线程。一个或多个线程能够阻塞等候一QWaitCondition ,用wakeOne()或wakeAll()设置一个条件。wakeOne()随机唤醒一个,wakeAll()唤醒所有。 下面的例子中,生产者首

11、先必须检查缓冲是否已满 (numUsedBytes==BufferSize),假如是,线程停下来等候bufferNotFull条件。假如不是,在缓冲中生产数据,增加numUsedBytes,激活条件 bufferNotEmpty。使用mutex来保护对numUsedBytes的访问。另外,QWaitCondition::wait()接收一个mutex作为参数,这个mutex应当被调用线程初始化为锁定状态。在线程进入休眠状态之前,mutex会被解锁。而当线程被唤醒时,mutex会处在锁定状态,并且,从锁定状态到等候状态的转换是原子操作,这制止了竞争条件的产生。当程序开始运行时,只有生产者能够工作

12、消费者被阻塞等候bufferNotEmpty条件,一旦生产者在缓冲中放入一个字节,bufferNotEmpty条件被激发,消费者线程于是被唤醒。 const int DataSize = 100000; const int BufferSize = 8192; char buffer[BufferSize]; QWaitCondition bufferNotEmpty; QWaitCondition bufferNotFull; QMutex mutex; int numUsedBytes = 0; class Producer : public QThread { pu

13、blic: void run(); }; void Producer::run() { qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); for (int i = 0; i < DataSize; ++i) { mutex.lock(); if (numUsedBytes == BufferSize) bufferNotFull.wait(&mutex); mutex.unlock(); buf

14、fer[i % BufferSize] = "ACGT"[(int)qrand() % 4]; mutex.lock(); ++numUsedBytes; bufferNotEmpty.wakeAll(); mutex.unlock(); } } class Consumer : public QThread { public: void run(); }; void Consumer::run() { for (int i = 0; i < DataSize; +

15、i) { mutex.lock(); if (numUsedBytes == 0) bufferNotEmpty.wait(&mutex); mutex.unlock(); fprintf(stderr, "%c", buffer[i % BufferSize]); mutex.lock(); --numUsedBytes; bufferNotFull.wakeAll(); mutex.unlock();

16、 } fprintf(stderr, "\n"); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); Producer producer; Consumer consumer; producer.start(); consumer.start(); producer.wait(); consumer.wait(); return 0; }   可重入与线程安全

17、在Qt文档中,术语“可重入”与“线程安全”被用来阐明一个函数怎样用于多线程程序。假如一个类的任何函数在此类的多个不一样的实例上,能够被多个线程同时调用,那么这个类被称为是“可重入”的。假如不一样的线程作用在同一个实例上仍能够正常工作,那么称之为“线程安全”的。 大多数c++类天生就是可重入的,因为它们经典地仅仅引用组员数据。任何线程能够在类的一个实例上调用这么的组员函数,只要没有别的线程在同一个实例上调用这个组员函数。举例来讲,下面的Counter 类是可重入的: class Counter { public: Counter() {n=0;} void

18、 increment() {++n;} void decrement() {--n;} int value() const {return n;} private: int n; }; 这个类不是线程安全的,因为假如多个线程都试图修改数据组员 n,成果未定义。这是因为c++中的++和--操作符不是原子操作。实际上,它们会被扩展为三个机器指令: 1,把变量值装入存储器 2,增加或减少存储器中的值 3,把存储器中的值写回内存 假如线程A与B同时装载变量的旧值,在存储器中增值,回写。他们写操作重叠了,导致变量值仅增加了一次。很

19、明显,访问应当串行化:A执行123步骤时不应被打断。使这个类成为线程安全的最简单措施是使用QMutex来保护数据组员: class Counter { public: Counter() { n = 0; } void increment() { QMutexLocker locker(&mutex); ++n; } void decrement() { QMutexLocker locker(&mutex); --n; } int value() const { QMutexLocker locker(&mutex); return n;

20、 } private: mutable QMutex mutex; int n; }; QMutexLocker类在结构函数中自动对mutex进行加锁,在析构函数中进行解锁。随便一提的是,mutex使用了mutable核心字来修饰,因为我们在value()函数中对mutex进行加锁与解锁操作,而value()是一个const函数。 大多数Qt类是可重入,非线程安全的。有某些类与函数是线程安全的,它们重要是线程有关的类,如QMutex,QCoreApplication::postEvent()。   线程与QObjects QThread 继承自Q

21、Object,它发射信号以指示线程执行开始与结束,并且也提供了许多slots。更有趣的是,QObjects能够用于多线程,这是因为每个线程被允许有它自己的事件循环。 QObject是可重入的。它的大多数非GUI子类,像QTimer,QTcpSocket,QUdpSocket,QHttp,QFtp,QProcess也是可重入的,在多个线程中同时使用这些类是也许的。需要注意的是,这些类被设计成在一个单线程中创建与使用,因此,在一个线程中创建一个对象,而在另外的线程中调用它的函数,这么的行为不能确保工作良好。有三种约束需要注意: 1,QObject的孩子总是应当在它爸爸被创建的那个线程中

22、创建。这意味着,你绝不应当传递QThread对象作为另一个对象的爸爸(因为QThread对象自身会在另一个线程中被创建) 2,事件驱动对象仅仅在单线程中使用。明确地说,这个规则适合用于"定期器机制“与”网格模块“,举例来讲,你不应当在一个线程中开始一个定期器或是连接一个套接字,当这个线程不是这些对象所在的线程。 3,你必须确保在线程中创建的所有对象在你删除QThread前被删除。这很轻易做到:你能够run()函数运行的栈上创建对象。 尽管QObject是可重入的,但GUI类,尤其是QWidget与它的所有子类都是不可重入的。它们仅用于根本程。正如前面提到过的,QCoreAppl

23、ication::exec()也必须从那个线程中被调用。实践上,不会在别的线程中使用GUI类,它们工作在根本程上,把某些耗时的操作放入独立的工作线程中,当工作线程运行完成,把成果在根本程所拥有的屏幕上显示。 逐线程事件循环 每个线程能够有它的事件循环,初始线程开始它的事件循环需使用QCoreApplication::exec(),别的线程开始它的事件循环需要用QThread::exec().像QCoreApplication同样,QThreadr提供了exit(int)函数,一个quit() slot。 线程中的事件循环,使得线程能够使用那些需要事件循环的非GUI 类(如,

24、QTimer,QTcpSocket,QProcess)。也能够把任何线程的signals连接到特定线程的slots,也就是说信号-槽机制是能够跨线程使用的。对于在QApplication之前创建的对象,QObject::thread()返回0,这意味着根本程仅为这些对象处理投递事件,不会为没有所属线程的对象处理另外的事件。能够用QObject::moveToThread()来变化它和它孩子们的线程亲缘关系,假如对象有爸爸,它不能移动这种关系。在另一个线程(而不是创建它的那个线程)中delete QObject对象是不安全的。除非你能够确保在同一时刻对象不在处理事件。能够用QObject::de

25、leteLater(),它会投递一个DeferredDelete事件,这会被对象线程的事件循环最后选用到。 假如没有事件循环运行,事件不会分发给对象。举例来说,假如你在一个线程中创建了一个QTimer对象,但从没有调用过exec(),那么QTimer就不会发射它的timeout()信号.对deleteLater()也不会工作。(这同样适合用于根本程)。你能够手工使用线程安全的函数QCoreApplication::postEvent(),在任何时候,给任何线程中的任何对象投递一个事件,事件会在那个创建了对象的线程中通过事件循环派发。事件过滤器在所有线程中也被支持,不过它限定被监视对象与监

26、视对象生存在同一线程中。类似地,QCoreApplication::sendEvent(不是postEvent()),仅用于在调用此函数的线程中向目标对象投递事件。 从别的线程中访问QObject子类 QObject和所有它的子类是非线程安全的。这包括整个的事件投递系统。需要紧记的是,当你正从别的线程中访问对象时,事件循环能够向你的QObject子类投递事件。假如你调用一个不生存在目前线程中的QObject子类的函数时,你必须用mutex来保护QObject子类的内部数据,否则会遭遇灾难或非预期成果。像其他的对象同样,QThread对象生存在创建它的那个线程中---不是当QTh

27、read::run()被调用时创建的那个线程。一般来讲,在你的QThread子类中提供slots是不安全的,除非你用mutex保护了你的组员变量。 另首先,你能够安全的从QThread::run()的实现中发射信号,因为信号发射是线程安全的。 跨线程的信号-槽 Qt支持三种类型的信号-槽连接: 1,直接连接,当signal发射时,slot立即调用。此slot在发射signal的那个线程中被执行(不一定是接收对象生存的那个线程) 2,队列连接,当控制权回到对象属于的那个线程的事件循环时,slot被调用。此slot在接收对象生存的那个线程中被执行 3,自动连接(

28、缺省),假如信号发射与接收者在同一个线程中,其行为如直接连接,否则,其行为如队列连接。 连接类型也许通过以向connect()传递参数来指定。注意的是,当发送者与接收者生存在不一样的线程中,而事件循环正运行于接收者的线程中,使用直接连接是不安全的。同样的道理,调用生存在不一样的线程中的对象的函数也是不是安全的。QObject::connect()自身是线程安全的。 多线程与隐含共享 Qt为它的许多值类型使用了所谓的隐含共享(implicit sharing)来优化性能。原理比较简单,共享类包括一个指向共享数据块的指针,这个数据块中包括了真正原数据与一个引用计数。把深拷贝转

29、化为一个浅拷贝,从而提升了性能。这种机制在幕后发生作用,程序员不需要关心它。假如深入点看,假如对象需要对数据进行修改,而引用计数不小于1,那么它应当先detach()。以使得它修改不会对别的共享者产生影响,既然修改后的数据与本来的那份数据不一样了,因此不也许再共享了,于是它先执行深拷贝,把数据取回来,再在这份数据上进行修改。例如: void QPen::setStyle(Qt::PenStyle style) { detach(); // detach from common data d->style = style; // set the

30、 style member } void QPen::detach() { if (d->ref != 1) { ... // perform a deep copy } } 一般以为,隐含共享与多线程不太友好,因为有引用计数的存在。对引用计数进行保护的措施之一是使用mutex,但它很慢,Qt早期版本没有提供一个满意的处理方案。从4.0开始,隐含共享类能够安全地跨线程拷贝,犹如别的值类型同样。它们是完全可重入的。隐含共享真的是"implicit"。它使用汇编语言实现了原子性引用计数操作,这比用mutex快多了。 假如你在多个线程中同进访问相同对象,你也需要用mutex来串行化访问次序,就犹如其他可重入对象那样。总的来讲,隐含共享真的给”隐含“掉了,在多线程程序中,你能够把它们当作是一般的,非共享的,可重入的类型,这种做法是安全的。

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服