首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • 关于工作线程中使用定时器的问题? [已结帖,结帖人:zhuyiwu]
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zhuyiwu
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 结帖率:
    发表于:2008-11-07 09:30:48 楼主
    最近在做一个上位机串口通信程序,工作原理如下述:
        利用一个工作线程来发送询问命令,等待接收到下位机应答数据后退出。如果两秒下位机未应答,则重发询问命令。重发10次下位机不应答,则认为通信故障,下面为相关代码(编程环境VC6.0):

    //启动线程代码(在一个菜单项响应函数中)/////////////////////////////////////////////////////////
    m_Thread = AfxBeginThread(SendCommand,this);  //this为一个CListView视图类
    if(m_Thread->m_hThread!=NULL)

          m_Thread->m_bAutoDelete=FALSE; 
          m_Thread->ResumeThread(); 
    }

    //线程内使用定时器相关代码//////////////////////////////////////////////////////
    UINT  CRecordreaderView::SendCommand(LPVOID lParam)            SendCommand为static函数
    {
    CRecordreaderView *m_pView = (CRecordreaderView *)lParam;
    /////////////////////
    发送查询命令相关代码
    ////////////////////
    ::SetTimer(m_pView->m_hWnd,1,2000,NULL);
    while(如果收到下位机应答则退出循环)                  //m_pView为指向当前CListView类的指针
    {
    if(m_pView->m_bReSend)          //判断是否应该重发
    {
          ////////////////////////////////
                          发送查询命令相关代码(重发)
                          ////////////////////////////////
          m_pView->m_bReSend=FALSE;
    }
    }
    ::KillTimer(m_pView->m_hWnd,1); 
    }

    ////////m_pView(CListView类中的Ontimer函数)//////////
    void CRecordreaderView::OnTimer(UINT nIDEvent)
    {
    CString temp;
    switch(nIDEvent)
    {
    case 1:
    m_iReSendcnt++;        //重发次数计数器,初始值为0
    if(m_iReSendcnt <10)
    {
                            m_bReSend=TRUE; //使线程重发查询命令
    }
    else
    {
            m_iReSendcnt=0;
            m_bReSend=FALSE;
            m_Thread->Delete();  //关闭发送线程
                            KillTimer(1);
            MessageBox("与下位机链接故障!请重新下载!");      
    }
                    break;

    }
    CListView::OnTimer(nIDEvent);
    }
        问题是如果下位机故障不应答的情况下,该定时器仅响应1次,线程重发1次查询命令,就停止了。线程将永远处于while循环里。在定时器响应函数内设置断点调试,发现定时器响应函数仅仅进入了1次。实在想不通为什么,想死的心都有了。那位大侠知道为什么?或者有保持线程发送查询命令的解决方案不变的情况下实现相同功能的其他方法还请赐教。感激不尽!!!!
        另外在该工作线程中通过ListView类指针调用自定义的公共函数,如果函数中有向CFrame类的状态栏写东东的代码,代码也会引起程序崩溃。而在主UI线程中进行同样的操作就没问题,这是为何?
    20  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • chenyu2202863
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-07 09:39:431楼 得分:0
    利用PostThreadMessage试,发送给主线程
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zhuyiwu
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-07 14:25:022楼 得分:0
    不明白怎么用PostThreadMessage在我这里实现上述功能,还请具体指教
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • IamNieo
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-08 01:55:513楼 得分:0
    你可以在while里面加个sleep(1)解决这个问题
    但是寒一个,你的这个程序框架是veryvery不安全的
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • paerxiushi
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-08 15:35:254楼 得分:10
    使用SetTimer有个前提条件,就是必须要有一个消息循环,例如:
    while(GetMessage(NULL,&msg,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    你可以不创建窗体的

    如果要在真正的工作线程中创建一个定时器,需要使用可等待定时器:
    这种定时器有两种使用方法,一种是设置信号的等待时间,这种方法需要使用WaitForSingleObject方法来响应定时处理
    另一种是设置回调函数的周期时间,
    第一方法代码:
    HANDLE hTimer = NULL;
        LARGE_INTEGER liDueTime;

        liDueTime.QuadPart=-100000000;

        // Create a waitable timer.
        hTimer = CreateWaitableTimer(NULL, TRUE, "WaitableTimer");
        if (!hTimer)
        {
            printf("CreateWaitableTimer failed (%d)\n", GetLastError());
            return 1;
        }

        printf("Waiting for 10 seconds...\n");

        // Set a timer to wait for 10 seconds.
        if (!SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0))
        {
            printf("SetWaitableTimer failed (%d)\n", GetLastError());
            return 2;
        }

        // Wait for the timer.

        if (WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0)
            printf("WaitForSingleObject failed (%d)\n", GetLastError());
        else printf("Timer was signaled.\n");

    第二种方法:
    参考这个网址:
    http://www.vckbase.com/document/viewdoc/?id=1587
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • paerxiushi
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-08 15:52:135楼 得分:10
    第一方法需要将WaitForSingleObject放在一个循环中,每次调用SetWaitableTimer来重置信号:

    HANDLE hTimer = NULL;
    LARGE_INTEGER liDueTime;

    liDueTime.QuadPart=-100000000;

    // Create a waitable timer.
    hTimer = CreateWaitableTimer(NULL, TRUE, _T("WaitableTimer"));
    if (!hTimer)
    {
    printf("CreateWaitableTimer failed (%d)\n", GetLastError());
    return 1;
    }

    printf("Waiting for 10 seconds...\n");

    // Set a timer to wait for 10 seconds.
    if (!SetWaitableTimer(hTimer, &liDueTime, 10, NULL, NULL, 0))
    {
    printf("SetWaitableTimer failed (%d)\n", GetLastError());
    return 2;
    }

    // Wait for the timer.
        while(true)
    {
    if (WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0)
    {
    printf("WaitForSingleObject failed (%d)\n", GetLastError());

    }
    else
    {
    printf("Timer was signaled.\n");
    SetWaitableTimer(hTimer,&liDueTime,0,NULL,NULL,0);
    }

    }
    这样一来,第10秒钟会显示出“Timer was signaled.”
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zhuyiwu
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-10 10:13:136楼 得分:0
    [Quote=引用   3   楼   IamNieo   的回复:]
    你可以在while里面加个sleep(1)解决这个问题  
    但是寒一个,你的这个程序框架是veryvery不安全的
    [/Quote]
    这个方法试了没有用啊.最后用线程同步的方法解决
    //初始化同步事件
    hTimer=::CreateEvent(NULL,FALSE,FALSE,NULL);


    //线程中的相关代码
    CRecordreaderView   *m_pView   =   (CRecordreaderView   *)lParam;  
    /////////////////////  
    发送查询命令相关代码  
    ////////////////////  
    while(::WaitForSingleObject(hTimer,2000)==WAIT_TIMEOUT   &&   m_pView-> m_iReSendcnt <10)
    {
              ////////////////////////////////  
              发送查询命令相关代码(重发)  
              ////////////////////////////////  
              m_pView-> m_iReSendcnt++;
    }
    m_pView-> m_iReSendcnt=0;


    //接收到下位机应答数据后
    ::SetEvent(hTimer);//置进程同步变量

    非常感谢各位大侠的帮助
    修改 删除 举报 引用 回复

    网站简介广告服务网站地图帮助联系方式诚聘英才English 问题报告
    北京创新乐知广告有限公司 版权所有 京 ICP 证 070598 号
    世纪乐知(北京)网络技术有限公司 提供技术支持
    Copyright © 2000-2008, CSDN.NET, All Rights Reserved