关于一个程序的“开始——暂停——继续”的一个问题

lsq19871207

关注

lsq19871207

信阳毛尖

本版等级:T7

结帖率:100%

Blank

楼主发表于: 2011-04-11 21:05:47

    要实现的功能就像360扫描一样,单击“开始”按钮,开始执行,此时按钮的Caption改变为“暂停”,再次单击这个按钮,程序接着上次暂停的地方继续执行。

    在我的程序中,OnBnClicked函数中,由于程序的需要,是创建一个线程,程序功能在线程函数中实现。线程函数主要部分是通过网卡循环向局域网各个主机发送报文并接收它们的响应报文进行相应的处理,其中又用到很多自定义的函数模块。
 

C/C++ code ?

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

void CGetMACDlg::OnBnClickedScanmac()

{

          /*................

          ..................

          ..................这些为打开本机网卡部分(为后面的发送——接收报文做准备)

          ..................

          */

          HWND h_wnd = ::GetDlgItem(this->m_hWnd,IDC_SCANMAC); 

    char* WinTitle=new char();

    int len = ::GetWindowTextLengthA(h_wnd);

    int x = ::GetWindowTextA( h_wnd,WinTitle,len+1); 

    CString str ="";

    str.Format("%s",WinTitle);

    CString str1 = "扫描";

    CString str2 = "暂停";

 

    if(str.Compare(str1))

    {

        ScanEthernet();//创建线程函数(CreateThread)

        ::SetWindowText(h_wnd,"暂停");

    }

    if(str.Compare(str2))

    {

                  。。。。。。。。。。。。//暂停线程(目前还不知如何写)

                  ::SetWindowText(h_wnd,"扫描");

    }

 

}



没有思绪了,貌似要用到信号量:
申请一个信号量:

hEvent=::CreateEvent(NULL,TURE,TURE,lpName);//第二个参数是TURE,设定为手动模式,防止::WaitForSingleObject改变信号量的状态。


在所有线程可以被暂停的地方加上:


::WaitForSingleObject(hEvent,-1);


这样,只需要用这两个函数


::SetEvent(hEvent);//继续
::ResetEvent(hEvent);//暂停

疑问一:如果用信号量的话,我这个程序改怎么改?“暂停”、“继续”函数具体加在什么地方?(如果这么用,我觉得线程中的循环可能会出问题,欢迎大家讨论一下)
疑问二:用SuspendThread  挂起(暂停)线程、ResumeThread  继续执行线程函数是否会好一些?
疑问三:程序逻辑上肯定存在问题,程序刚启动按钮自然是“扫描”状态,第一次单击逻辑没有问题,创建线程执行;第二次单击,暂停线程,逻辑也没有问题,当第三次单击时,逻辑就有问题了:应该是继续执行线程,而不是再次创建线程。
改成这样:

C/C++ code ?

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

void CGetMACDlg::OnBnClickedScanmac()

{

          /*................

          ..................

          ..................这些为打开本机网卡部分(为后面的发送——接收报文做准备)

          ..................

          */

          HWND h_wnd = ::GetDlgItem(this->m_hWnd,IDC_SCANMAC); 

    char* WinTitle=new char();

    int len = ::GetWindowTextLengthA(h_wnd);

    int x = ::GetWindowTextA( h_wnd,WinTitle,len+1); 

    CString str ="";

    str.Format("%s",WinTitle);

    CString str1 = "扫描";

    CString str2 = "暂停";

 

         ScanEthernet();//创建线程函数(CreateThread)

    ::SetWindowText(h_wnd,"暂停");

 

    if(str.Compare(str2))

    {

                  。。。。。。。。。。。。//暂停线程(目前还不知如何写)

                  ::SetWindowText(h_wnd,"扫描");

    }

    if(str.Compare(str1))

    {

                  。。。。。。。。。。。。//继续线程(目前还不知如何写)

                  ::SetWindowText(h_wnd,"暂停");

    }

 

}


好像逻辑也不对!!!

初次接触这个东西,望大家指教!!

 

更多0分享到:

  •  
  •  
  •  

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

回复次数:30

mfcing

关注

mfcing

疯狂-的-蜗牛

本版等级:T5

#1 得分:5回复于: 2011-04-11 21:07:37

顶一下,你比我强多了,我不知道呵呵、

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

jennyvenus

关注

jennyvenus

智能卡_Snooper

本版等级:T10

Blank Blank Blank更多勋章

#2 得分:5回复于: 2011-04-11 21:18:17

开始、暂停、继续 用一个变量就行了
 

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

aa_qq110

关注

aa_qq110

秦剑

本版等级:T3

#4 得分:5回复于: 2011-04-11 21:20:40

SuspendThread(m_hHandle); 
m_hHandle是你Create的线程的句柄

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

Devil26

关注

Devil26

Devil26

本版等级:T2

#5 得分:5回复于: 2011-04-11 21:23:29

创建一个BOOL变量表明是否需要创建线程,如果第一次当然创建,之后点击就不用创建了,不知道对不对哦

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

jennyvenus

关注

jennyvenus

智能卡_Snooper

本版等级:T10

Blank Blank Blank更多勋章

#6 得分:10回复于: 2011-04-11 21:24:49

C/C++ code ?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

int run = 0;

int step = 0;

 

on_click_run

{

    run = !run;

    click_start();

}

 

click_start()

{

    do

    {

        if( !run )

        {

            return;

        }

        else

        {

            do_some_thing( step );

            step++;

        }

    while( 1 );

}

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

VisualEleven

关注

VisualEleven 版主

Eleven

本版等级:T12

Blank Blank Blank更多勋章

#7 得分:30回复于: 2011-04-11 21:25:37

疑问一: CreateSemphore/ReleaseSemaphore,和EVENT的处理差不多的,SetEvent/ReSetEvent()

疑问二:不建议使用SuspendThread/ResumeThread();因为SuspendThread和ResumeThread的作用其实很简单,他们都是通过线程的HANDLE到线程的数据结构中将一个计数的变量做加一减一的操作, 如果线程在运行时监测到线程的Suspend Count计数大于0,那么线程就会暂停处理任何消息和循环的进行,这时CPU将不为该线程分配时间片,如果线程的Suspend Count小于等于0,线程将正常运行。所以ResumeThread的一次调用并不一定导致线程的运行,SuspendThread也不一定导致线程挂起,关键在于线程的挂起计数。

疑问三:判断一下是否存在

C/C++ code ?

1

2

3

4

5

6

static BOOL bScan = FALSE;

::SetWindowText(h_wnd, (bScan = !bScan) ?  _T("扫描") : _T("暂停"));

if(bScan)

{

  // 创建线程

}

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

aa_qq110

关注

aa_qq110

秦剑

本版等级:T3

#8 得分:5回复于: 2011-04-11 21:27:12

DWORD WINAPI SuspendThread(
  __in  HANDLE hThread
); // 暂停

DWORD WINAPI ResumeThread(
  __in  HANDLE hThread
);// 重新开始
http://msdn.microsoft.com/en-us/library/ms682453(v=vs.85).aspx

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

huangcheng90

关注

huangcheng90

Dreadnought

本版等级:T7

#9 得分:5回复于: 2011-04-11 21:31:40

创建个BOOL型的变量用来判断

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

King_hhuang

关注

King_hhuang

King_hhuang

本版等级:T7

Blank Blank

#10 得分:20回复于: 2011-04-11 21:32:51

程序"开始"时创建线程,你需要执行的操作放到线程中的while循环中,循环中每次判断WaitForSingleObject(_hEvent, INFINITE);

如果需要"继续",SetEvent(_hEvent);
需要"暂停",ResetEvent(_hEvent);
看看这个程序,不知道让你对Event的用法有些启发:

C/C++ code ?

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

#include <windows.h>

#include <iostream>

using namespace std;

 

DWORD WINAPI Fun1Proc(LPVOID lpParameter);

DWORD WINAPI Fun2Proc(LPVOID lpParameter);

 

int tickets=100;

HANDLE g_hEvent;

 

void main()

{

HANDLE hThread1;

HANDLE hThread2;

 

//**************************************************

//创建一个命名的自动重置事件内核对象

 

g_hEvent=CreateEvent(NULL,TRUE,FALSE,LPCTSTR("tickets"));

  

if (g_hEvent)

{

if (ERROR_ALREADY_EXISTS==GetLastError())

{

cout<<"only one thread can run!"<<endl;

return;

}

}

 

//**************************************************

SetEvent(g_hEvent);

 

//创建线程

hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);

hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);

 

Sleep(40000);

//关闭事件对象句柄

CloseHandle(g_hEvent);

};

 

DWORD WINAPI Fun1Proc(LPVOID lpParameter)

{

while (TRUE)

{

WaitForSingleObject(g_hEvent, INFINITE);

 

BOOL bReSet = ResetEvent(g_hEvent);

 

if (tickets>0)

{

cout<<"thread 1 sell ticket :"<<tickets--<<endl;

}

else

{

break;

}

SetEvent(g_hEvent);

Sleep(10);

}

 

return 0;

};

 

DWORD WINAPI Fun2Proc(LPVOID lpParameter)

{

while (TRUE)

{

WaitForSingleObject(g_hEvent, INFINITE);

 

BOOL bReSet = ResetEvent(g_hEvent);

 

if (tickets>0)

{

Sleep(1);

cout<<"thread 2 sell ticket :"<<tickets--<<endl;

}

else

{

break;

}

SetEvent(g_hEvent);

Sleep(10);

}

 

return 0;  

};

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

luchao002

关注

luchao002

走走刀口

本版等级:T3

#11 得分:5回复于: 2011-04-11 21:38:11

使用PV操作

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

heksn

关注

heksn

写不动代码的人

本版等级:T8

Blank Blank

#12 得分:5回复于: 2011-04-11 22:00:35

hEvent=::CreateEvent(NULL,TURE,TURE,lpName);//第二个参数是TURE,设定为手动模式,防止::WaitForSingleObject改变信号量的状态。


在所有线程可以被暂停的地方加上:


::WaitForSingleObject(hEvent,-1);


这样,只需要用这两个函数


::SetEvent(hEvent);//继续
::ResetEvent(hEvent);//暂停
 

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

samako

关注

samako

samako

本版等级:T1

#13 得分:5回复于: 2011-04-11 23:24:57

路过的,看下

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

wmnmtm

关注

wmnmtm

wmnmtm

本版等级:T3

#14 得分:5回复于: 2011-04-11 23:58:24

线程应该不退出,只是判断那个全局变量,如果处于暂停,那么就忽略对应的执行代码吧。

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

hztj2005

关注

hztj2005

hztj2005

本版等级:T7

#15 得分:20回复于: 2011-04-12 00:25:38

没有多难吧

code=C/C++]

//设置两个全局变量或CGetMACDlg成员函数标记
   bool juststart=0;//
   bool nowstate=0;
void CGetMACDlg::OnBnClickedScanmac()
{
          /*................
          ..................
          ..................这些为打开本机网卡部分(为后面的发送——接收报文做准备)
          ..................
          */
   
    HWND h_wnd = ::GetDlgItem(this->m_hWnd,IDC_SCANMAC); 
    char* WinTitle=new char();
    int len = ::GetWindowTextLengthA(h_wnd);
    int x = ::GetWindowTextA( h_wnd,WinTitle,len+1);        

    if(nowstate==0)
    {
if(juststart==0){//刚启动
ScanEthernet();//创建线程函数(CreateThread)
juststart=1;//已经启动
nowstate=1;
::SetEvent(hEvent);//执行线程
::SetWindowText(h_wnd,"暂停")
nowstate=1;

}else{
//继续线程
::SetEvent(hEvent);//继续
nowstate=1;
::SetWindowText(h_wnd,"暂停")

}     
                  
    }else
{   //暂停线程

         ::ResetEvent(hEvent);//暂停
 nowstate=0;
         ::SetWindowText(h_wnd,"扫描");;
    }

}

[/code]

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

b245930557

关注

b245930557

b245930557

本版等级:T1

#16 得分:5回复于: 2011-04-12 00:49:49

无论你是使用临界区对象、互锁函数、事件内核对象、信号量内核对象还是互斥内核对象,原理都差不多,也很简单

至于点第三次就出现错误,我猜想是创建线程的缘故吧,点第三次的时候你又创建了第二个线程额

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

xiaopoy

关注

xiaopoy

xiaopoy

本版等级:T4

#17 得分:5回复于: 2011-04-12 01:00:04

在循环的函数里是否继续处理下一个的地方加上对信号量的判断不就可以了?

一般的应用,Event实现的接口能算绰绰有余了。

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

xiaopoy

关注

xiaopoy

xiaopoy

本版等级:T4

#18 得分:5回复于: 2011-04-12 01:18:14

我刚在没看内容瞎说话:

我觉得你的需要,这样实现的话应该可以做到比较简单的管理
每个线程的参数都作为传递它要扫描对象的参数。
线程在开始处理这堆对象里的一个之前的当前处理数量的判断里,也判断下自己对应的信号,从二个原因判断出来是不是允许它执行下去,当然在判断信号的地方可以用Wait的方式等待就更好。不然其他的暂停处理也可以在判断循环的这儿进行暂停。
在主线程或者单独一个线程的里面,维护一份线程使用的结构列表,比方结构里就保存着线程所处理的目标们,控制线程用的句柄,还有它所申请的内存片等需要释放的数据也放在里面,当然还有决定它暂停与执行的变量。
这样在主线程里,需要处理某个目标时,直接在这个列表里找有没有对应的线程,没就创建,有就设置执行的变量。需要暂停就寻找有没有对应的线程,有就设置暂停的变量。
当结束处理某个目标,或者就在换目标进行处理的时候想结束掉对其他目标的处理,那就在监视线程结构列表的流程里做一个释放线程用数据的函数,直接释放了再Kill那个Thread就好了。

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

gongdiwudu

关注

gongdiwudu

无水先生

本版等级:T5

#20 得分:5回复于: 2011-04-12 07:00:29

思路:
     1)建立通信模块Ccomm ,该摸块有堵塞/通信功能,相信从现有类里不难实现.
     2)建立通信块的序列Ccomm m_cmm[25];
     3)只用一个线程,该线程扫描序列m_cmm.用静态变亮记述当前序列位置
      4)在Ccomm中记录通信状态

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

jyh_baoding

关注

jyh_baoding

jyh_baoding

本版等级:T7

#21 得分:5回复于: 2011-04-12 08:15:29

都是自己定义的逻辑控制,记录当前状态就可以了,知道当前的什么状态就好操作了

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

qiuxin425

关注

qiuxin425

qiuxin425

本版等级:T5

#22 得分:4回复于: 2011-04-12 09:16:29

设置一个BOOL变量,为真给线程发操作事件,为假不发,用timer时钟来发 

就可以实现运行  暂停  继续啦 

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

xianglitian

关注

xianglitian 版主

向立天

本版等级:T10

Blank Blank Blank更多勋章

#23 得分:30回复于: 2011-04-12 09:51:45

小兄弟
我给你做了一个小例子
不敢说实现有多么合理
不过应该会给你些启示
有兴趣的话留个邮箱

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

lsq19871207

关注

lsq19871207

信阳毛尖

本版等级:T7

Blank

#24 得分:0回复于: 2011-04-12 11:14:23

引用 23 楼 xianglitian 的回复:
小兄弟
我给你做了一个小例子
不敢说实现有多么合理
不过应该会给你些启示
有兴趣的话留个邮箱

感激不尽!!!!
有劳大哥发一下:
569051911@qq.com

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

lsq19871207

关注

lsq19871207

信阳毛尖

本版等级:T7

Blank

#25 得分:0回复于: 2011-04-12 11:17:10

顺便问一下:
WaitForSingleObject(xxxx,INFINITE)函数在我的这个程序当中,应该放在线程处理函数当中的 数据包发送与接收这个循环 的前面吧?

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

xianglitian

关注

xianglitian 版主

向立天

本版等级:T10

Blank Blank Blank更多勋章

#26 得分:0回复于: 2011-04-12 11:42:12

我发了
你查收

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

King_hhuang

关注

King_hhuang

King_hhuang

本版等级:T7

Blank Blank

#27 得分:5回复于: 2011-04-12 11:45:05

引用 25 楼 lsq19871207 的回复:
顺便问一下:
WaitForSingleObject(xxxx,INFINITE)函数在我的这个程序当中,应该放在线程处理函数当中的 数据包发送与接收这个循环 的前面吧?

放在你的业务操作开始前

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

murphy0410

关注

murphy0410

忽悠

本版等级:T2

#28 得分:3回复于: 2011-04-12 11:46:12

我是新手说下我的方法,我做的是批量文件转换,定义BOOL类型的变量 m_bRun,初始化index为0,index为文件个数,这样控制m_bRun的值可以实现暂停和继续功能
for (;index<m_list.GetItemCount();index++)
{
try
{
转换函数。。 }
catch(_com_error e)
{
CString errorMessage=e.ErrorMessage();
AfxMessageBox(_T("出错")+errorMessage);//显示错误信息
}
if (!m_bRun)//暂停
{
index++;
break;
}

}
if (index==m_list.GetItemCount())
{
MessageBox(_T("全部完成!"));
}

if(index>=m_list.GetItemCount())
{
index = 0;

}

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

smwhotjay

关注

smwhotjay

smwhotjay

本版等级:T7

#29 得分:3回复于: 2011-04-12 12:08:39

Event,很好. 我就用Event写了个线程池. 

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理

lsq19871207

关注

lsq19871207

信阳毛尖

本版等级:T7

Blank

#30 得分:0回复于: 2011-04-12 14:06:54

万事开头难,经过大家的指导,这个功能已经实现,先谢谢大家!

现总结一下:

创建线程函数ScanEthernet
1、在线程创建的时候申请信号量,如我的程序:

C/C++ code ?

1

2

3

4

5

6

7

void CGetMACDlg::ScanEthernet()

{   

    g_hEvent=::CreateEvent(NULL,TRUE,FALSE,NULL);

    HANDLE hThread=CreateThread(NULL,0,PacketRec,(LPVOID)this,0,NULL);

    CloseHandle(hThread);

     

}




2、根据程序的需要,在线程处理函数中添加WaitForSingleObject(g_hEvent, INFINITE)函数,在我的程序中,是在for循环中开始位置添加的 ,因为这个发送数据包循环是线程处理函数的主体部分,程序运行起来后除了初始化,就是通过这个循环来实现其功能,因此,加在循环外自然是不合理的
3、在单击按钮处理函数中,根据自身程序的需要,添加
::ResetEvent(g_hEvent);//暂停 
和 
::SetEvent(g_hEvent);//继续

注意:

CreateEvent(NULL,TRUE,FALSE,NULL)函数的第二个参数一定要设置为TRUE,即手动模式,防止::WaitForSingleObject改变信号量的状态,一开始我就把其设置为FALSE,结果是单击按钮时,只循环执行一次,而且会出现“继续”与“暂停”执行效果相反的情况,这就是WaitForSingleObject本身改变信号量的状态 所造成的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值