Qt线程基础(这个比较完整)

2012-11-09  来源:本站原创  分类:Qt  人气:6 

线程基础

保谓线程?

线程与并行处理任务息息相关,就像进程一样。那么,线程与进程有什么区别呢?当你在电子表格上进行数据结算的时候,在相同的桌面上可能有一个播放器正在播放你最喜欢的歌曲。这是一个两个进程并行工作的例子:一个进程运行电子表格程序;另一个进程运行一个媒体播放器。这种情况最适合用多任务这个词来描述。进一步观察媒体播放器,你会发现在这个进程内,又存在并行的工作。当媒体播放器向音频驱动发送音乐数据的时候,用户界面上与之相关的信息不断地进行更新。这就是单个进程内的并行线程。

那么,线程的并行性是如何实现的呢?在单核CPU计算机上,并行工作类似在电影院中不停移动图像产生的一种假象。对于进程而言,在很短的时间内中断占有处理器的进程就形成了这种假象。然而,处理器迁移到下一个进程。为了在不同进程之间进行切换,当前程序计算器被保存,下一个程序计算器被加载进来。这还不够,相关寄存器以及一些体系结构和操作系统特定的数据也要进行保存和重新加载。

就像一个CPU可以支撑两个或多个进程一样,同样也可以让CPU在单个进程内运行不同的代码片段。当一个进程启动时,它问题执行一个代码片断从而该进程就被认为是拥有了一个线程。但是,该程序可以会决定启动第二个线程。这样,在一个进程内部,两个不同的代码序列就需要被同步处理。通过不停地保存当前线程的程序计数器和相关寄存器,同时加载下一个线程的程序计数器和相关寄存器,就可以在单核CPU上实现并行。在不同活跃线程之间的切换不需要这些线程之间的任何协作。当切换到下一个线程时,当前线程可能处于任一种状态。

当前CPU设计的趋势是拥有多个核。一个典型的单线程应用程序只能利用一个核。但是,一个多线程程序可被分配给多个核,便得程序以一种完全并行的方式运行。这样,将一个任务分配给多个线程使得程序在多核CPU计算机上的运行速度比传统的单核CPU计算机上的运行速度快很多。

GUI 线程和工作者线程

如上所述,每个程序启动后就会拥有一个线程。该线程称为”主线程”(在Qt应用程序中也叫”GUI线程”)。Qt GUI必须运行在此线程上。所有的图形元件和几个相关的类,如QPixmap,不能工作于非主线程中。非主线程通常称为”工作者线程”,因为它主要处理从主线程中卸下的一些工作。

数据的同步访问

每个线程都有自己的栈,这意味着每个线程都拥有自己的调用历史和本地变量。不同于进程,同一进程下的线程之间共享相同的地址空间。下图显示了内存中的线程块图。非活跃线程的程序计数器和相关寄存器通常保存在内核空间中。对每个线程来说,存在一个共享的代码片段和一个单独的栈。

Qt线程基础(这个比较完整)

如果两个线程拥有一个指向相同对象的指针,那么两个线程可以同时去访问该对象,这可以破坏该对象的完整性。很容易想象的情形是一个对象的两个方法同时执行可能会出错。

有时,从不同线程中访问一个对象是不可避免的。例如,当位于不同线程中的许多对象之间需要进行通信时。由于线程之间使用相同的地址空间,线程之间进行数据交换要比进程之间进行数据交换快得多。数据不需要序列化然后拷贝。线程之间传递指针是允许的,但是必须严格协调哪些线程使用哪些指针。禁止在同一对象上执行同步操作。有一些方法可以实现这种要求,下面描述其中的一些方法。

那么,怎样做才安全呢?在一个线程中创建的所有对象在线程内部使用是安全的,前提条件是其他线程没有引用该线程中创建的一些对象且这些对象与其他的线程之间没有隐性耦合关系。当数据作为静态成员变量,单例或全局数据方式共享时,这种隐性耦合是可能发生的。

使用线程

基本上,对线程来讲,有两种使用情形:

· 利用多核处理器使处理速度更快。

· 将一些处理时间较长或阻塞的任务移交给其他的线程,从而保证GUI线程或其他对时间敏感的线程保持良好的反应速度。

何时不应使用线程

开发者在使用线程时必须特意小心。启动其他线程很容易,但很难保证所有共享的数据仍然是一致的。这些问题通常很难找到,因为它们可以在某个时候仅显示一次或仅在某种硬件配置下出现。在创建线程解决某些问题之前,如下的一些方法也应该考虑一下。


非线程方式


说明


QEventLoop::processEvents()


在一个耗时的计算中不停地调用QEventLoop::processEvents()能以免GUI被阻塞。但是,这种解决方式并不能用于更大范围的计算操作中,因为会导致调用 processEvents()太频繁或不够,取决于硬件。.


QTimer


有时,在后台进程中使用一个计时器来调度在将来某个时间点运行一段程序非常方便。超时时间为0的计时器将在事件处理完后立即触发。


QSocketNotifierQNetworkAccessManagerQIODevice::readyRead()


当在一个低速的网络连接上进行阻塞读的时候,可以不使用多线程。只要对一块网络数据的计算可以很快地执行,那么,这种交互式的设计比线程中的同步等待要好些。交互式设计比多线程要不容易出错且更有效。在许多情况下,也有一些性能上的提升。

一般来讲,建议只使用安全的且已被验证过的路径,避免引入线程概念。 QtConcurrent提供了一种简易的接口,来将工作分配到所有的处理器的核上。线程相关代码已经完全隐藏在QtConcurrent 框架中,因此,开发者不需要关注这些细节。但是, QtConcurrent 不能用于那么需要与运行中的线程进行通信的情形,且它也不能用于处理阻塞操作。

该使用哪种 Qt 线程技术?

有时,我们不仅仅只是在另一个线程中运行一个方法。可能需要位于其他线程中的某个对象为GUI线程提供服务。也许,你想其他的线程一直保持活跃状态去不停地轮询硬件端口并在一个需要关注的事件发生时发送一个信号给GUI线程。Qt提供了不同的解决方案来开发多线程应用程序。正确的解决方案取决于新线程的目的以及它的生命周期。


线程的生命周期


开发任务


解决方案


单次调用


在其他的线程中运行一个方法,当方法运行结束后退出线程。


Qt 提供了不同的解决方案:

· 1.编写一个函数,然后利用 QtConcurrent::run()运行它。

· 2.从QRunnable 派生一个类,并利用全局线程池QThreadPool::globalInstance()->start()来运行它。

· 3. 从QThread派生一个类, 重载QThread::run() 方法并使用QThread::start()来运行它。


单次调用


在容器中的所有项执行相同的一些操作。执行过程中使用所有可用的核。一个通用的例子就是从一个图像列表中产生缩略图。


QtConcurrent 提供了 map()函数来将这些操作应用于于容器中的每个项中,filter() 用于选择容器元素,以及指定一个删减函数的选项来与容器中剩下的元素进行合并。


单次调用


一个耗时的操作必须放到另一个线程中运行。在这期间,状态信息必须发送到GUI线程中。


使用 QThread,,重载run方法并根据情况发送信号。.使用queued信号/槽连接来连接信号与GUI线程的槽。


常驻


有一对象位于另一个线程中,将让其根据不同的请求执行不同的操作。这意味与工作者线程之间的通信是必须的。


QObject 派生一个类并实现必要的槽和信号,将对象移到一个具有事件循环的线程中,并通过queued信号/槽连接与对象进行通信。


常驻


对象位于另一个线程中,对象不断执行重复的任务如轮询某个端口,并与GUI线程进行通信。


与上述类似,但同时在工作者线程中使用一个计时器来实现轮询。但是,最好的解决方案是完全避免轮询。有时,使用 QSocketNotifier 是一种不错的选择。

Qt 线程基础

QThread 是对本地平台线程的一个非常好的跨平台抽象。启动一个线程非常简单。让我们看一段代码,它产生另一个线程,该线程打印hello,然后退出。

  1. // hellothread/hellothread.h
  2. class HelloThread : public QThread
  3. {
  4. Q_OBJECT
  5. private:
  6. void run();
  7. };

我们从QThread 中派生一个类并重载run()方法。

  1. // hellothread/hellothread.cpp
  2. void HelloThread::run()
  3. {
  4. qDebug() << "hello from worker thread " << thread()->currentThreadId();
  5. }

run方法中包含的代码会运行于一个单独的线程。在本例中,一条包含线程ID的信号将会被输出来。QThread::start() 会在另一个线程中调用该方法。

  1. int main(int argc, char *argv[])
  2. {
  3. QCoreApplication app(argc, argv);
  4. HelloThread thread;
  5. thread.start();
  6. qDebug() << "hello from GUI thread " << app.thread()->currentThreadId();
  7. thread.wait(); // do not exit before the thread is completed!
  8. return 0;
  9. }

为了启动该线程,我们的线程对象必须被初始化。start() 方法创建了一个新的线程并在新线程中调用重载的run() 方法。 在 start() 被调用后,有两个程序计数器走过程序代码。主函数启动,且仅有一个GUI线程运行,它停止时也只有一个GUI线程运行。当另一个线程仍然忙碌时退出程序是一种编程错误,因此, wait方法被调用用来阻塞调用的线程直到run()方法执行完毕。

下面是运行代码的结果:

hello from GUI thread 3079423696

hello from worker thread 3076111216

QObject 和线程

一个 QObject 通常被认为有线程亲和力 或换句话说, 它位于某个线程中。这意味着,在创建的时候, QObject保存了一个指向当前线程的指针。当一个事件利用 postEvent()发出时,该信息就变得有关了。该事件将会被放于对应线程的事件循环中。如果QObject位于的线程没有事件循环,那么事件就不会被传递。

为了启动一个事件循环,exec() 必须在 run()里面调用. 线程亲和力可使用moveToThread()来改变。如上所述,开发者从其他线程中调用对象的方法时必须非常小心。线程亲和力并没有改变这种状况。Qt文档标记了几个方法是线程安全的。 postEvent() 是一个很明显的例子。一个线程安全的方法可以在不同的线程中同时被调用。

在没有并行访问方法的情况下,在其他线程中调用对象的非线程安全的方法时可能运行了几千次后才会出现一个并发访问,造成不可预料的行为。编写测试代码并不能完全的保证线程的正确性,但仍然很重要。在Linux中,Valgrind和Helgrind可以侦测线程错误。

QThread 细节非常有意思:

· QThread 并不位于新线程 run()执行的位置中。它位于旧线程中。

· 大部分QThread 的方法是线程的控制接口中,并在旧线程中调用。不要使用moveToThread()将这些接口移到新创建的线程中,例如,调用moveToThread(this) 被认为是一种坏的实践。

· exec()和静态方法usleep(), msleep(), sleep()应在新创建的线程中调用。

其他的一些定义在 QThread 子类中的成员可以在新旧线程中访问。开发者负责协调这些访问。 一种典型的策略是在调用 start() 前设置这些成员。一旦工作者线程运行起来,主线程不应当再修改这些成员。当工作者线程停止后,主线程又可以访问些额外的成员。这是一种在线程启动前和停止后传递参数的方便的策略。

一个 QObject's 父类必须位于相同的线程中。对于run()方法中创建的对象,在这有一个非常惊人的结果。

  1. void HelloThread::run()
  2. {
  3. QObject *object1 = new QObject(this); //error, parent must be in the same thread
  4. QObject object2; // OK
  5. QSharedPointer <QObject> object3(new QObject); // OK
  6. }

使用一个互斥量 来保护数据的完整性

一个互斥量是一中且具有lock() 和 unlock() 方法的对象,并记住它是否被锁住。互斥量可在多个线程中访问。如果互斥量没有被锁定, lock() 会立即返回。下一个从其他线程的调用会发现互斥量已经处于锁定状态,然后,lock() 会阻塞线程直到其他线程调用 unlock()。该功能可保证一个代码段在同一时间仅能被一个线程执行。

下面代码显示了怎样使用一个互斥量来确保一个方法是线程安全的。

  1. void Worker::work()
  2. {
  3. this->mutex.lock(); // first thread can pass, other threads will be blocked here
  4. doWork();
  5. this->mutex.unlock();
  6. }

如果一个线程不能解锁一个互斥量会发生什么情况呢?结果是应用程序会僵死。在上面的例子中,可以会抛出异常且永远不会到达mutex.unlock() 。为了防止这种情况,应该使用 QMutexLocker 。

  1. void Worker::work()
  2. {
  3. QMutexLocker locker(&mutex); // Locks the mutex and unlocks when locker exits the scope
  4. doWork();
  5. }

这看上去很简单,但互斥会引入新的问题:死锁。当一个线程等待一个互斥量变为解锁,但是该互斥量仍然处于锁定状态,因为占有该互斥量的线程在等待第一个线程解锁该互斥量。结果是一个僵死的应用程序。互斥量用于保证一个方法是线程安全的。大部分Qt方法不是线程安全的,因为当使用互斥量时总是有些性能损失。

在一个方法中并不总是能够加锁和解锁一个互斥量。有时,锁定的范围跨越了数个调用。例如,利用迭代器修改一个容器时需要几个调用组成的序列,这个序列不能被其他线程中断。在这种情况下,利用外部锁就可以保证这个调用序列是被锁定的。利用一个外部锁,锁定的时间可以根据操作的需要进行调整。不好之处是外部锁帮助锁定,但不能强制执行它,因为对象的使用者可能忘记使用它。

使用事件循环来防止数据崩溃

Qt的事件循环对线程间通信是一个非常有价值的工具。每个线程可以拥有自己的事件循环。调用另一个线程中的槽的安全方法就是将此调用放在该线程的事件循环中。这确保了目标对象在启动另一方法前完成了当前正在执行的方法。那么,怎样将一个方法调用放到一个事件循环中呢?Qt有两种方式。一种方式是通过queued信号-槽连接;另一种方式就是利用QCoreApplication::postEvent()发送一个事件。一个queued 信号-槽连接是一种异步执行的信号槽连接。内部实现是基于发送的事件。信号的参数放置到事件循环中,信号方法会立即返回。

连接的槽执行的时间取决于事件循环中的基于事件。通过事件循环通信消除了使用互斥量面临的死锁问题。这就是为什么我们建议使用事件循环而不是使用互斥量锁定一个对象。

处理异步执行

一种获得工作者线程结果的方式是等待该线程停止。然而,在许多情况下,阻塞的等待是不可接受的。另一种方式是通过发送的事件或queued信号和槽来获得异步结果。这产生了一些开销,因为一个操作的结果并不是出现在下一个代码行,而是在一个位于其他地方的槽中。Qt开发者习惯了这种异步行为,因为它与GUI应用程序中事件驱动的方式非常类似。

例子

该手册提供了一些例子,演示了在Qt中使用线程的三种基本方法。另外两个例子演示了怎样与一个运行中的线程进行通信以及一个 QObject 可被置于另一个线程中,为主线程提供服务。

· 使用 QThread 使用如上所示。

· 使用全局的QThreadPool

· 使用 QtConcurrent

· 与GUI线程进行通信

· 在另一个线程的常驻对象为主线程提供服务

如下 的例子可以单独地进行编译和运行。源码可在源码目录中找到:examples/tutorials/threads/

例 1: 使用Thread Pool

不停地创建和销毁线程非常耗时,可以使用一个线程池。线程池可以存取线程和获取线程。我们可以使用全局线程池写一个与上面相同的"hello thread" 程序 。我们从QRunnable派生出一个类。在另一个线程中运行的代码必须放在重载的QRunnable::run()方法中。

  1. // hellothreadpool/main.cpp
  2. class Work : public QRunnable
  3. {
  4. public:
  5. void run()
  6. {
  7. qDebug() << "Hello from thread " << QThread::currentThread();
  8. }
  9. };
  10. int main(int argc, char *argv[])
  11. {
  12. QCoreApplication app(argc, argv);
  13. Work work;
  14. work.setAutoDelete(false);
  15. QThreadPool *threadPool = QThreadPool::globalInstance();
  16. threadPool->start(&work);
  17. qDebug() << "hello from GUI thread " << QThread::currentThread();
  18. threadPool->waitForDone();
  19. return 0;
  20. }

在main()中, 我们实例化了Work, 定位于全局的线程池,使用QThreadPool::start()方法。现在,线程池在另一个线程中运行我们的工作。 使用线程池有一些性能上的优势,因为线程在它们结束后没有被销毁,它们被保留在线程池中,等待之后再次被使用。

例 2: 使用 QtConcurrent

  1. // helloconcurrent/main.cpp
  2. void hello()
  3. {
  4. qDebug() << "Hello from thread " << QThread::currentThread();
  5. }
  6. int main(int argc, char *argv[])
  7. {
  8. QCoreApplication app(argc, argv);
  9. QFuture<void> future = QtConcurrent::run(hello);
  10. qDebug() << "hello from GUI thread " << QThread::currentThread();
  11. future.waitForFinished();
  12. return 0;
  13. }

我们写一个全局的函数hello()来实现工作者代码。QtConcurrent::run()用于在另一个线程中运行该函数。该结果是QFuture。 QFuture 提供了一个方法叫waitForFinished(), 它阻塞主线程直到计算完成。当所需的数据位于容器中时,QtConcurrent才显示它真正的威力。 QtConcurrent 提供了一些函数能并行地处理这些已经成为容器里元素的一些数据。使用QtConcurrent非常类似于应用一个STL算法到某个STL容器类。QtConcurrent Map是一个非常简短且清晰的例子,它演示了容器中的图片怎么被扩散到所有核中去处理。对于每个阻塞函数,都同时存在一个非阻塞, 异步型函数。异步地获取结果是通过QFuture 和QFutureWatcher来实现的。

例 3: Clock

Qt线程基础(这个比较完整)

我们想创建一个时钟应用程序。该应用程序有一个GUI和一个工作者线程。工作者线程每10毫秒检查一下当前的时间。如果格式化的时间发生了变化,该结果会发送给显示时间的GUI线程当中。

当然, 这是一种过度复杂的方式来设计一个时钟,事实上,一个独立的线程没必要。使用计时器会更好。本例子纯粹是用于教学目的的,演示了从工作者线程向GUI线程进行通信。 注意,这种通信方式非常容易,我们仅需要添加一个信号给QThread, 然后构建一个queued 信号/槽连接到主线程中。从GUI到 工作者线程的方式在下一个例子中演示。

  1. int main(int argc, char *argv[])
  2. {
  3. QApplication app(argc, argv);
  4. // build gui
  5. QWidget widget;
  6. QLabel *label = new QLabel;
  7. QHBoxLayout *layout = new QHBoxLayout(&widget);
  8. layout->addWidget(label);
  9. widget.setWindowTitle("clock");
  10. //instantiate thread object
  11. ClockThread clockThread;
  12. QObject::connect(&clockThread, SIGNAL(sendTime(QString)), label, SLOT(setText(QString)), Qt::QueuedConnection);
  13. clockThread.start();
  14. widget.show();
  15. app.exec();
  16. clockThread.quit();
  17. clockThread.wait();
  18. return 0;
  19. }

我们已经将 clockThread 与标签连接起来。连接必须是一个queued 信号-槽连接,因为我们想将调用放到事件循环当中。

  1. // clock/clockthread.h
  2. class ClockThread : public QThread
  3. {
  4. Q_OBJECT
  5. signals:
  6. void sendTime(QString time);
  7. private:
  8. void run();
  9. QString m_lastTime;
  10. private slots:
  11. void timerHit();
  12. };

我们从 QThread 派生出一个类,并声明sendTime()信号。

  1. // clock/clockthread.cpp
  2. void ClockThread::run()
  3. {
  4. QTimer timer;
  5. connect(&timer, SIGNAL(timeout()), this, SLOT(timerHit()), Qt::DirectConnection);
  6. timer.setInterval(10);
  7. timer.start(); // puts one event in the threads event queue
  8. exec();
  9. timer.stop();
  10. }
  11. void ClockThread::timerHit()
  12. {
  13. QString newTime= QDateTime::currentDateTime().toString("ddd MMMM d yy, hh:mm:ss");
  14. if(m_lastTime != newTime ){
  15. m_lastTime = newTime;
  16. emit sendTime(newTime) ;
  17. }
  18. }

该例子中最值得关注的部分是计时器通过一个直接连接与它的槽相连。默认的连接会产生一个queued 信号-槽连接,因为被连接的对象位于不同的线程。记住,QThread并不位于它创建的线程中。但是,从工作者线程中访问ClockThread::timerHit() 仍然是安全的,因为ClockThread::timerHit()是私有的,且只处理私有变量。QDateTime::currentDateTime() 在Qt文档中并未标记为线程安全的,但是在此例子中,我们可以放心使用,因为我们知道访方法没有会其他的线程中使用。

例 4: A 常驻线程

该例子演示了位于工作者线程中的一个QObject接受来自GUI线程的请求,利用一个计时器进行轮询,并不时地将结果返回给GUI线程。实现的工作包括轮询必须实现在一个从QObject派生出的类中。在如下代码中,我们已称该类为 WorkerObject。 线程相关的代码已经隐藏在称为Thread类中,派生自QThread. Thread有两个额外的公共成员。launchWorker() 获取工作者对象并将其移到另一个开启了事件循环的线程中。 该调用阻塞一小会,直到创建操作完成,使得工作者对象可以在下一行被再次使用。Thread 类的代码短但有点复杂,因此我们只显示怎样使用该类。

  1. // movedobject/main.cpp
  2. int main(int argc, char *argv[])
  3. {
  4. QCoreApplication app(argc, argv);
  5. Thread thread;
  6. qDebug() << "main thread ID: " << app.thread()->currentThreadId();
  7. WorkerObject *worker = new WorkerObject;
  8. thread.launchWorker(worker);
  9. QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);
  10. QMetaObject::invokeMethod(worker, "startPolling", Qt::QueuedConnection, Q_ARG(int, 500));
  11. //let application produce output for 3 seconds and quit
  12. QTimer::singleShot(3000, &app, SLOT(quit()));
  13. app.exec();
  14. thread.stop();
  15. thread.wait();
  16. delete worker;
  17. return 0;
  18. }

QMetaObject::invokeMethod()通过事件循环调用槽。worker对象的方法不应该在对象被移动到另一个线程中直接调用。我们让工作者线程执行一个工作和轮询,并使用一个计时器在3秒后关闭该应用程序。关闭worker需要当心。我们调用 Thread::stop() 退出事件循环。我们等待线程停止,当线程停止后,我们删除worker。

相关文章
  • Qt线程基础(这个比较完整) 2012-11-09

    线程基础 保谓线程? 线程与并行处理任务息息相关,就像进程一样.那么,线程与进程有什么区别呢?当你在电子表格上进行数据结算的时候,在相同的桌面上可能有一个播放器正在播放你最喜欢的歌曲.这是一个两个进程并行工作的例子:一个进程运行电子表格程序;另一个进程运行一个媒体播放器.这种情况最适合用多任务这个词来描述.进一步观察媒体播放器,你会发现在这个进程内,又存在并行的工作.当媒体播放器向音频驱动发送音乐数据的时候,用户界面上与之相关的信息不断地进行更新.这就是单个进程内的并行线程. 那么,线程的并行性

  • Qt 线程基础(QThread.QtConcurrent.QThreadPool等) 2012-11-08

    使用线程 基本上有种使用线程的场合: 通过利用处理器的多个核使处理速度更快. 为保持GUI线程或其他高实时性线程的响应,将耗时的操作或阻塞的调用移到其他线程. 何时使用其他技术替代线程 开发人员使用线程时需要非常小心.启动线程是很容易的,但确保所有共享数据保持一致很难.遇到问题往往很难解决,这是由于在一段时间内它可能只出现一次或只在特定的硬件配置下出现.在创建线程来解决某些问题之前,应该考虑一些替代的技术 : 替代技术 注解 QEventLoop::processEvents() 在一个耗时的计

  • Qt 线程基础(QThread.QtConcurrent等) 2012-11-10

    昨晚看Qt的Manual,突然发现下一个版本的Qt中(Qt4.7.4.Qt4.8等)增加了一个特赞的介绍多线程的文章 : Thread Basics 注意: 该链接以后会失效,但是 到时候你直接看Qt自带Manual就行了 本文不是严格的翻译 dbzhang800 2011.06.18 使用线程 基本上有种使用线程的场合: 通过利用处理器的多个核使处理速度更快. 为保持GUI线程或其他高实时性线程的响应,将耗时的操作或阻塞的调用移到其他线程. 何时使用其他技术替代线程 开发人员使用线程时需要非常

  • .NET 线程基础的使用介绍 2014-11-18

    本篇文章介绍了,.NET 线程基础的使用说明,需要的朋友参考下 线程作用及开销 早期计算机一次只能运行一个程序,长时间执行程序容易出现计算机"瘫痪"的问题,如果程序进入死循环则只能重启系统.即使计算机不崩溃,也难免让用户崩溃.为了解决这个问题,操作系统设计者设计出了进程的概念,使得每个应用程序运行在一个虚拟的内存空间中.进程中又包含多个线程,CPU则根据操作系统调度执行每个进程中的线程任务.通过线程这种对CPU的虚拟化管理方式,操作系统形成了多任务执行的机制.但与一切虚拟化机制一样,线

  • qt线程----部分代码片段 2012-11-09

    一.把视频显示到界面的方法 (1)针对qt4的(视频格式为rgb32) v4l_grab_movie(&v4l_dev); unsigned char *pBuffer= v4l_dev.buffer; QImage image(pBuffer,320,240,QImage::Format_RGB32); QPixmap pixmap; pixmap=pixmap.fromImage(image); label->setPixmap(pixmap); label->setFixedSi

  • Qt线程和定时器[一] 2014-08-14

    新的线程run里面一定要有exec的调用,否则无法接受消息的. class myQThr : public QThread { Q_OBJECT public: myQThr(QObject *in = NULL) :QThread(in) { WrTimer = new QTimer(this); connect(WrTimer, SIGNAL(timeout()), this, SLOT(TimerOutWr1()), Qt::DirectConnection); WrTimer->star

  • QT线程与定时器[二] 2014-08-14

    下面转一个相关说明吧 实例代码1: class MThread :public QThread { public: MThread(); ~MThread(); virtual void run(); void foo(); ... }; POINT 1:QThread类的实例与普通类的实例没什么不同,只是运行着的run()函数会不同 实例代码2: class MDialog :public QDialog { ... MThread *mythread; }; MDialog::MDialog

  • Qt下几个线程函数介绍 2012-11-09

    1.QCoreApplication::processEvents() 2.每个线程可以有它的事件循环,初始线程开始它的事件循环需使用QCoreApplication::exec(),别的线程开始它的事件循环需要用QThread::exec().像QCoreApplication一样,QThreadr提供了exit(int)函数,一个quit() slot. 线程安全的函数QCoreApplication::postEvent(),在任何时候,给任何线程中的任何对象投递一个事件,事件会在那个创建

  • Qt的多线程编程注意事项 2014-04-01

    QT总的来说是一个易学易用的库, 但是QT的多线程使用确实容易犯错,尤其是结合上异步的网络访问,谁用谁知道.我觉得核心是一句话,QThread要当作线程控制块用,不要以为派生一个QThread的子类,里面的东西都跑在新的线程里了,只有run()里的是这样. 下面这篇文章我觉得讲的很好,深入解析QT的线程用法,文章有点长,但是值得一读. 原文在 http://qt-project.org/wiki/ThreadsEventsQObjects 译文在 http://www.cppblog.com/b

  • JVM 并发性: Java 和 Scala 并发性基础 2015-01-03

    处理器速度数十年来一直持续快速发展,并在世纪交替之际走到了终点.从那时起,处理器制造商更多地是通过增加核心来提高芯片性能,而不再通过增加时钟速率来提高芯片性能.多核系统现在成为了从手机到企业服务器等所有设备的标准,而这种趋势可能继续并有所加速.开发人员越来越需要在他们的应用程序代码中支持多个核心,这样才能满足性能需求. 在本系列文章中,您将了解一些针对 Java 和 Scala 语言的并发编程的新方法,包括 Java 如何将 Scala 和其他基于 JVM 的语言中已经探索出来的理念结合在一起.

  • (转)Python线程指南 2012-02-21

    本文介绍了Python对于线程的支持,包括"学会"多线程编程需要掌握的基础以及Python两个线程标准库的完整介绍及使用示例. 注意:本文基于Python2.4完成,:如果看到不明白的词汇请记得百度谷歌或维基,whatever. 尊重作者的劳动,转载请注明作者及原文地址 >.< 1. 线程基础 1.1. 线程状态 线程有5种状态,状态转换的过程如下图所示: 1.2. 线程同步(锁) 多 线程的优势在于可以同时运行多个任务(至少感觉起来是这样).但是当线程需要共享数据时,可能

  • Python线程指南 2013-08-27

    1. 线程基础 1.1. 线程状态 线程有5种状态,状态转换的过程如下图所示: 1.2. 线程同步(锁) 多 线程的优势在于可以同时运行多个任务(至少感觉起来是这样).但是当线程需要共享数据时,可能存在数据不同步的问题.考虑这样一种情况:一个列表里所有元 素都是0,线程"set"从后向前把所有元素改成1,而线程"print"负责从前往后读取列表并打印.那么,可能线程"set"开始改的时候,线 程"print"便来打印列表了,输

  • 多线程:终止线程 2014-07-07

    线程启动之后,在运行时可能需要终止,终止方法只有stop,但是不建议使用这个的方法. 原因: 1:stop方法是过时的 java编码中过时的方法不建议使用 2:stop方法会导致代码逻辑不完整 这是一种强行的中断,不管线程的逻辑是否完整,都会清除栈内信息,这是非常危险的做法.因为我们不知道子线程执行到什么时候被终止,根本不知道!!! 3:stop方法破坏了原子逻辑 多线程为了解决共享资源的抢占问题,使用了锁的概念,避免资源不同步,但是正因为此原因.stop方法带来了更大的问题.它会舍弃所有的锁,

  • 初级必备:Java版本区别与了解_JavaSE_线程小结 2014-11-28

    链接地址:http://www.xx566.com/detail/99.html java.lang.Thread类是传统java用来调度和管理线程的工具,其提供了多种方法来操控线程:从java 5开始,Java提供了Java.util.concurrent工具包用来进行并发编程,并引入了lock,其提供了Condition接 口,Condition实例实质被绑定在一个lock上,通过其提供的方法,也可以方便的对线程进行调度和管理,一系列眼花缭乱的方法:sleep(). join().yield

  • XMPP-IM方案分析 2014-07-16

    1. 概述 1.1 Jabber & Xmpp Jabber(XMPP- Extensible Messaging and Presence Protocol)协议,是一个开源的即时消息协议,建立在jabber协议上的IM客户端可以互连.关于XMPP的两个官方网http://www.xmpp.org/ 和http://www.jabber.org/. 支持jabber协议的IM软件非常多 其中包括开源不开源的.参见: http://www.jabber.org/clients(全部开源),主要以

  • [转贴] 游戏服务器架构二 2010-03-24

    来自:http://www.libing.net.cn/read.php/1724.htm 服务器公共组件实现 -- 环形缓冲区 消息队列锁调用太频繁的问题算是解决了,另一个让人有些苦恼的大概是这太多的内存分配和释放操作了.频繁的内存分配不但增加了系统开销,更使得内存碎片不断增多,非常不利于我们的服务器长期稳定运行.也许我们可以使用内存池,比如SGI STL中附带的小内存分配器.但是对于这种按照严格的先进先出顺序处理的,块大小并不算小的,而且块大小也并不统一的内存分配情况来说,更多使用的是一种叫

  • 最流行的Node.js精简型和全栈型开发框架介绍 2014-03-30

    这篇文章主要介绍了最流行的Node.js精简型和全栈型开发框架介绍,本文讲解了Express.js.KOA.Total.js.Sails.js.Meteor.Mean.IO等框架,需要的朋友可以参考下 快速开发而又容易扩展,高性能且鲁棒性强.Node.js的出现让所有网络应用开发者的这些梦想成为现实.但是,有如其他新的开发语言技术一样,从头开始使用Node.js的最基本功能来编写代码构建应用是一个非常划不来的耗时的事情.这个问题的解决方案非常简单且已经经受起时间的考验:使用一个已经提前打造好的开

  • C#转C++的一点分享 2014-04-27

    前几天看到这样一篇博客<那些年·我们读过的专业书籍>,里面列了很多大家认为很好的书,加上自己在自学C++的工程中也看了不少书,感觉并不是所有的书都值得花时间去看的,毕竟很多人一年下来也看不了2,3本书,不同的技术能力的人,适合看的书都不太一样,在这么多大家都认为是经典的书中,选出几本真正适合自己的才是王道,经典一多了,有些比起来就不是那么经典了,当然大家都说经典,自然有可看之处,如果有多余的时间,多看些书自然是好的. 下面是我看过的技术书籍(不一定看完),还有本<程序员的自我修养>

  • Objective-C并发编程:API和挑战 2014-07-20

    并发指的是在同一时间运行多个任务.在单核CPU的情况下,它通过分时的方式实现,如果有多个CPU可用,则是真正意义上的多个任务"并行"执行了. OS X和iOS提供了多个API支持并发编程.每个API都有自己特殊的功能和限制,适用于完成不同的任务.它们也分布在不同的抽象层次,我们可以通过底层API去做些非常接近硬件的底层操作,但这样的话,我们也需要做更多的事去保证一切运行正常. 并发编程是件非常棘手的事,有着许多复杂的问题和陷阱,而且在使用像GCD或NSOperationQueue这样的

  • 信息化普及 企业实施ERP十大反思 2014-12-27

    随着信息技术的发展和市场竞争的加剧,越来愈多的企业开始应用各种信息化技术武装自己.从五六十年代的EDP.七八十年代的MIS.MRPII到九十年代的CIMS和近期的ERP,企业信息化经历了从单纯的数据处理到信息管理.从闭环系统走向开环系统.从局部单项管理到全局综合管理的发展阶段.在当前的企业信息化工作中,ERP正成为应用中的热点.不论是国内的,还是国外的IT厂商,都纷纷推出自己的ERP产品以及系列解决方案,企业该如何面对ERP的应用热潮呢?也许,在市场发热的时候,我们更有必要清醒头脑,深入理解ER