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盘插入会自动装载,拔出自动卸载。