• C++ 线程的创建、挂起、唤醒和结束 &&&& 利用waitForSingleObject 函数陷入死锁的问题解决


    最近在写一个CAN总线的上位机软件,利用CAN转USB的设备连到电脑上,进行数据的传输。在接收下位机发送的数据的时候采用的在线程中持续接收数据。

    1、在连接设备的函数中,开启线程。

    //在创建线程的时候,将线程挂起,挂起的线程可设置下面的m_bAutoDelete 等属性,再进行线程的唤醒

    m_pThread = AfxBeginThread(ReceiveThread,this,0,CREATE_SUSPENDED,NULL);
    m_pThread->m_bAutoDelete = false;

    2、线程唤醒

    ResumeThread(m_pThread->m_hThread);

    3、线程挂起

    SuspendThread(m_pThread->m_hThread);

    4、线程结束

    线程结束呢,网上最推荐的方法是线程函数正常返回,即某个变量达到某个标准,退出循环,结束线程。

    UINT CTest_OilDlg::ReceiveThread(void *param)
    {
        while(1)
        {
            Sleep(1);
            if(dlg->m_connect == 0)
            {
                break;
            }
                    //   其他操作
         }
    }             

    上面满足m_connect == 0,即设备断开该循环就结束,线程函数就会进行正常返回。在结束线程的地方写如下代码

    ::WaitForSingleObject(m_pThread->m_hThread,INFINITE);
    delete m_pThread;
    m_pThread = NULL;//不太懂
    WaitForSingleObject该函数是等待线程运行结束,即线程结束后置空线程。但是在使用该函数的时候,子线程里面不能有更新界面的操作,比如更新某个控件。因为这个函数是个阻塞函数,不仅阻塞线程也会阻塞消息。也就是说该函数要等待线程结束,而线程中如果有更新界面的操作,则需要界面的这个主线程给一个反应,但是此时界面的主线程被waitForSingleObject函数阻塞着,也就是进入了一个死锁的境遇。
    这个时候可以改用MsgWaitForMultipleObjects这个函数,这个函数是微软针对waitForSingleObject会阻塞消息给出的一个函数,MsgWaitForMultipleObjects不会阻塞消息。
    也就是上面的代码可以改写成如下:
        
    DWORD dwRet = 0;
                MSG msg;
                while(true)
                {
                    //等待处理数据线程结束,和等待消息队列中的任何消息
                    dwRet = MsgWaitForMultipleObjects(1,&m_pThread->m_hThread,false,INFINITE,QS_ALLINPUT);
                    //dwRet = WaitForSingleObject(m_pThread->m_hThread,50);
                    switch (dwRet)
                    {
                    case WAIT_OBJECT_0:
                            break;
                    case WAIT_OBJECT_0 + 1:
                        //get the message from Queue and dispatch it to specific window
                        PeekMessage(&msg,NULL,0,0,PM_REMOVE);
                        DispatchMessage(&msg);
                        continue;
                    default:
                        break;
                    }
                    break;
                }
                //CloseHandle(m_pThread->m_hThread);
                delete m_pThread;
                m_pThread = NULL;//不太懂

    关于WaitForMultipleObjects(参考https://www.cnblogs.com/shangdawei/p/4015772.html

    DWORD WaitForMultipleObjects(
    DWORD dwCount, //等待的内核对象个数
    CONST HANDLE* phObjects, //一个存放被等待的内核对象句柄的数组
    BOOL bWaitAll, //是否等到所有内核对象为已通知状态后才返回
    DWORD dwMilliseconds); //等待时间
    HANDLE h[3]; //句柄数组
    //三个进程句柄
    h[0] = hProcess1;
    h[1] = hProcess2;
    h[2] = hProcess3;
    DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000); //等待3个进程结束
    switch (dw)
    {
      case WAIT_FAILED:
      // 函数呼叫失败
      break;
       
      case WAIT_TIMEOUT:
      // 超时
      break;
       
      case WAIT_OBJECT_0 + 0:
      // h[0](hProcess1)所代表的进程结束
      break;
       
      case WAIT_OBJECT_0 + 1:
      // h[1](hProcess2)所代表的进程结束
      break;
       
      case WAIT_OBJECT_0 + 2:
      // h[2](hProcess3)所代表的进程结束
      break;
    }
  • 相关阅读:
    初识Mysql 连接器的收获(包含JDBC API最新文档)以及一些c++的有用技巧
    重拾 ”多项式“ 给我的启示
    vs2015下配置MySQL,使之能使用c++连接完美运行
    在CentOS上使用yum安装java
    CentOS 用yum安装中文输入法
    Redhat Linux RHEL5配置CentOS YUM更新源
    转:Linux下which、whereis、locate、find 命令的区别
    Centos 挂载NTFS格式的USB硬盘
    scp采用无密码在两台linux服务器之间传输数据
    转:Andriod studio技巧合集
  • 原文地址:https://www.cnblogs.com/ling123/p/8653580.html
Copyright © 2020-2023  润新知