1 线程 线程,就是操作系统所能调度的最小单位。普通的进程,只有一个线程在执行对应的逻辑。我们可以通过多线程编程,使一个进程可以去执行多个不同的任务。相比多进程编程而言,线程享有共享资源,即在进程中出现的全局变量,每个线程都可以去访问它,与进程共享内存空间,使得系统资源消耗减少。
2 QT中多线程的实现 官方文档里说, QThread 类提供了一种独立于平台的方法来管理线程。 QThread 对象在程序中管理一个控制线程。 QThreads 在 run()中开始执行。默认情况下, run()通过调用 exec()来启动事件循环,并在线程中运行 Qt 事件循环。您可以通过使用 QObject::moveToThread()将 worker对象移动到线程来使用它们。
QThread 线程类是实现多线程的核心类。 Qt 有两种多线程的方法,其中一种是继承 QThread的 run()函数,另外一种是把一个继承于 QObject 的类转移到一个 Thread 里。 Qt4.8 之前都是使用继承 QThread 的 run()这种方法,但是 Qt4.8 之后, Qt 官方建议使用第二种方法。本文使用第一种方法,继承 QThread的 run()函数。
3 U盘的自动挂载和卸载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 QString MyThreadCheckDevice::CheckIsDevice (int plug_sock) { char buf[2048 ] = {0 }; recv (plug_sock, &buf, sizeof (buf), 0 ); QString result = buf; int flag = 0 ; while (result.contains ("add" )||result.contains ("remove" )) { result = buf; if (result.contains ("add" )) { flag = 1 ; if (result.contains ("sda1" )) { system ("mount /dev/sda1 /opt/SD" ); sync (); printf ("sda1.....mount ok!!...........\n" ); } else if (result.contains ("sdb1" )) { system ("mount /dev/sdb1 /opt/SD" ); sync (); printf ("sdb1......mount ok!!.............\n" ); } else if (result.contains ("sdc1" )) { system ("mount /dev/sdc1 /opt/SD" ); sync (); printf ("sdc1....mount ok!!................\n" ); } } else if (result.contains ("remove" )) { flag = 0 ; if (result.contains ("sda1" )) { system ("umount /dev/sda1" ); sync (); printf ("---------------umount sda1-----------------------\n" ); } else if (result.contains ("sdb1" )) { system ("umount /dev/sdb1" ); sync (); printf ("---------------umount sdb1------------------------\n" ); } else if (result.contains ("sdc1" )) { system ("umount /dev/sdc1" ); sync (); printf ("----------------umount sdc1------------------------\n" ); } } memset (buf,0 ,1024 ); if (flag){ return "SDOK" ; } else return "SDUMOUNT" ; } } static int init_hotplug_sock (void ) { struct sockaddr_nl snl; const int buffersize = 16 * 1024 * 1024 ; int retval; memset (&snl, 0x00 , sizeof (struct sockaddr_nl)); snl.nl_family = AF_NETLINK; snl.nl_pid = getpid (); snl.nl_groups = 1 ; int hotplug_sock = socket (PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); if (hotplug_sock == -1 ) { printf ("error getting socket: %s" , strerror (errno)); return -1 ; } setsockopt (hotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof (buffersize)); retval = bind (hotplug_sock, (struct sockaddr *) &snl, sizeof (struct sockaddr_nl)); if (retval < 0 ) { printf ("bind failed: %s" , strerror (errno)); close (hotplug_sock); hotplug_sock = -1 ; return -1 ; } return hotplug_sock; }
4 工程创建 主线程内有很多方法在主线程内, 但是子线程,只有 run()方法是在子线程里的。 run()方法是继承于 QThread 类的方法,用户需要重写这个方法,一般是把耗时的操作写在这个 run()方法里面。
(1)在之前的工程基础上,添加多线程应用,包括mythread.h、mythread.cpp、mythread.ui。
(2)设计ui界面
如图所示
(3)创建两个继承 QThread 的线程,其中线程1的功能是数字每一秒加一,并显示在屏幕中;线程2的功能是监控USB,实现U盘的自动挂载以及卸载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class MyThreadNum : public QThread{ Q_OBJECT public : MyThreadNum (QWidget *parent) { Q_UNUSED (parent); } void run () ; signals: void ResultReadyNum (const QString &s) ; }; class MyThreadCheckDevice : public QThread{ Q_OBJECT public : MyThreadCheckDevice (QWidget *parent) { Q_UNUSED (parent); } void run () ; QString CheckIsDevice (int plug_sock) ; signals: void ResultReadyCheckDevice (const QString &s) ; };
(4)实例化两个线程
1 2 3 4 5 ThreadNum = new MyThreadNum (this ); ThreadCheckDevice = new MyThreadCheckDevice (this );
(5)重写run()函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 void MyThreadNum::run () { QString result = "MyThreadNum start OK!" ; while (1 ) { sleep (1 ); qDebug ()<<"MyThreadNum is Runing!" ; emit ResultReadyNum (result) ; } } void MyThreadCheckDevice::run () { int hotplug_sock= init_hotplug_sock (); QString result; while (1 ) { result = CheckIsDevice (hotplug_sock); emit ResultReadyCheckDevice (result) ; } }
(6)在mythread类中定义两个函数,用来接收线程的信号,若开启线程成功,则屏幕会有相应的动作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 void mythread::handleResultsNum (const QString &result) { static int i; qDebug ()<<result<<endl; i++; if (i > 100 ) i = 0 ; ui->lcdNumber->display (i); } void mythread::handleResultsCheckDevice (const QString &result) { qDebug ()<<result<<endl; static int flag = 0 ; qDebug ()<<flag<<endl; if (!result.compare ("SDOK" ) && flag == 0 ){ flag = 1 ; LQToast *toast = new LQToast; toast->setAlignment (LQToast::Custom); toast->setText ("检测到U盘插入" ); toast->setBackgroundColor (QColor ("white" )); toast->show (); ui->LineEditThread2->setText ("U盘已挂载" ); } if (!result.compare ("SDUMOUNT" )){ flag = 0 ; LQToast *toast = new LQToast; toast->setAlignment (LQToast::Custom); toast->setText ("U盘已拔出" ); toast->setBackgroundColor (QColor ("white" )); toast->show (); ui->LineEditThread2->setText ("U盘已卸载" ); } }
(7)连接线程和mythread类中定义的函数
1 2 3 4 5 connect (ThreadNum, SIGNAL (ResultReadyNum (QString)), this , SLOT (handleResultsNum (QString))); connect (ThreadCheckDevice, SIGNAL (ResultReadyCheckDevice (QString)), this , SLOT (handleResultsCheckDevice (QString)));
(8)使用按钮开启线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void mythread::on_PbThread1_released () { if (!ThreadNum->isRunning ()) ThreadNum->start (); } void mythread::on_PbThread2_released () { if (!ThreadCheckDevice->isRunning ()) ThreadCheckDevice->start (); }
5 移植到开发板运行
点击线程1按钮,数字每一秒加一,并显示在屏幕中。
点击线程2按钮,U盘插入会自动装载,拔出自动卸载。