我现在有一个线程一直在修改一个全局变量,比如线程一直将变量a赋值为1,然后我现在想通过一个按钮事件,点击一下就先打断线程,将a赋值为2进行一些数据处理,处理完后再交还线程继续为1,写了一个模拟的程序,大概如下HANDLE hEvent = NULL;void adddata();
BOOL bTrun = true;
int a =0;
void ListenerProcess(LPVOID lpParameter) //用于监听文件夹中是否有新文件需要更新
{
while(bTrun)
{
if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)
{
a = 1;
}
adddata();
}
ExitThread(0);
}void adddata()
{
ResetEvent(hEvent);
if(a == 2)
{
::MessageBox(NULL,"进入了","进入了",MB_OK);
}
SetEvent(hEvent);}//然后按钮点击置为2
void CTestDlg::OnButton1() 
{

if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)
{
a = 2;
}
}这样做结果还是概率性成功,请大虾赐教

解决方案 »

  1.   

    while(bTrun)
        {
            if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)
            {
                a = 1;
            }    
            adddata();
        }    
        ExitThread(0);你这个事件又是怎么触发的,这要想清楚
      

  2.   

    首先 在你的代码里 你只是创建了一个句柄 hEvent  根本没有创建事件...不知道是不是你没贴出来
    然后 WaitForSingleObject()成功后 自动重置的内核事件会被自动设为无信号状态,不需要调用ResetEvent()。
    再就是 OnButton1等待成功后根本没有把事件设为有信号状态。
    最最重要的是 在WaitForSingleObject和ResetEvent之间的操作时不会被等待同一个事件的线程打断的。按照这种思路,这个程序永远不会成功。偶尔成功是因为你实际上根本没有完成线程同步的操作。
      

  3.   

    这样如何int pause =0;
    void ListenerProcess(LPVOID lpParameter)    //用于监听文件夹中是否有新文件需要更新 
    {
         while(bTrun)     
         {        
             if( pause == 0) 
             { 
               if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) 
               {      a = 1;     } 
                adddata();   
             } 
         }        
         ExitThread(0); 

    //然后按钮点击置为2 
    void CTestDlg::OnButton1()  
    {  
       pause = 1;        
        if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)    
        {         a = 2;     } 
       pause = 0;
    }
      

  4.   

    还是不行呢,点击没有反应呢// CAboutDlg dialog used for App About
    HANDLE hEvent = NULL;
    int pause =0;
    void adddata();
    BOOL bTrun = true;
    int a =0;
    void ListenerProcess(LPVOID lpParameter)    //用于监听文件夹中是否有新文件需要更新
    {
    while(bTrun)     
    {        
    if( pause == 0) 

    if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) 
    {     
    a = 1;   
    }   

    adddata(); 
    }        
         ExitThread(0); 
    }void adddata()
    {
        ResetEvent(hEvent);
        if(a == 2)
        {
            ::MessageBox(NULL,"进入了","进入了",MB_OK);
        }
        SetEvent(hEvent);

    }
    class CAboutDlg : public CDialog
    {
    public:
    CAboutDlg();// Dialog Data
    //{{AFX_DATA(CAboutDlg)
    enum { IDD = IDD_ABOUTBOX };
    //}}AFX_DATA // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CAboutDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL// Implementation
    protected:
    //{{AFX_MSG(CAboutDlg)
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
    {
    //{{AFX_DATA_INIT(CAboutDlg)
    //}}AFX_DATA_INIT
    }void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CAboutDlg)
    //}}AFX_DATA_MAP
    }BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    //{{AFX_MSG_MAP(CAboutDlg)
    // No message handlers
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
    // CTestDlg dialogCTestDlg::CTestDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CTestDlg::IDD, pParent)
    {
    //{{AFX_DATA_INIT(CTestDlg)
    // NOTE: the ClassWizard will add member initialization here
    //}}AFX_DATA_INIT
    // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }void CTestDlg::DoDataExchange(CDataExchange* pDX)
    {
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CTestDlg)
    // NOTE: the ClassWizard will add DDX and DDV calls here
    //}}AFX_DATA_MAP
    }BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
    //{{AFX_MSG_MAP(CTestDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
    // CTestDlg message handlersBOOL CTestDlg::OnInitDialog()
    {
    CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
    CString strAboutMenu;
    strAboutMenu.LoadString(IDS_ABOUTBOX);
    if (!strAboutMenu.IsEmpty())
    {
    pSysMenu->AppendMenu(MF_SEPARATOR);
    pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    }
    } // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE); // Set big icon
    SetIcon(m_hIcon, FALSE); // Set small icon
    pThread = AfxBeginThread( (AFX_THREADPROC)adddata,
    NULL,
    THREAD_PRIORITY_NORMAL,
    0,
    0,
    NULL);
    hEvent = CreateEvent(NULL,TRUE,TRUE,NULL);
    // TODO: Add extra initialization here

    return TRUE;  // return TRUE  unless you set the focus to a control
    }void CTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
    CAboutDlg dlgAbout;
    dlgAbout.DoModal();
    }
    else
    {
    CDialog::OnSysCommand(nID, lParam);
    }
    }// If you add a minimize button to your dialog, you will need the code below
    //  to draw the icon.  For MFC applications using the document/view model,
    //  this is automatically done for you by the framework.void CTestDlg::OnPaint() 
    {
    if (IsIconic())
    {
    CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle
    int cxIcon = GetSystemMetrics(SM_CXICON);
    int cyIcon = GetSystemMetrics(SM_CYICON);
    CRect rect;
    GetClientRect(&rect);
    int x = (rect.Width() - cxIcon + 1) / 2;
    int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon
    dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
    CDialog::OnPaint();
    }
    }// The system calls this to obtain the cursor to display while the user drags
    //  the minimized window.
    HCURSOR CTestDlg::OnQueryDragIcon()
    {
    return (HCURSOR) m_hIcon;
    }void CTestDlg::OnButton1() 
    {
    pause = 1;        
        if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)    
        {        
    a = 2;    

    pause = 0;
    }
      

  5.   

    是这样,改错个地方,但是还是没有反应的// CAboutDlg dialog used for App About
    HANDLE hEvent = NULL;
    int pause =0;
    void adddata();
    BOOL bTrun = true;
    int a =0;
    void ListenerProcess(LPVOID lpParameter)    //用于监听文件夹中是否有新文件需要更新
    {
    while(bTrun)     
    {        
    if( pause == 0) 

    if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) 
    {     
    a = 1;   
    }  
    adddata();

     
    }        
         ExitThread(0); 
    }void adddata()
    {
        ResetEvent(hEvent);
        if(a == 2)
        {
            ::MessageBox(NULL,"进入了","进入了",MB_OK);
        }
        SetEvent(hEvent);

    }
    class CAboutDlg : public CDialog
    {
    public:
    CAboutDlg();// Dialog Data
    //{{AFX_DATA(CAboutDlg)
    enum { IDD = IDD_ABOUTBOX };
    //}}AFX_DATA // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CAboutDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL// Implementation
    protected:
    //{{AFX_MSG(CAboutDlg)
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
    {
    //{{AFX_DATA_INIT(CAboutDlg)
    //}}AFX_DATA_INIT
    }void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CAboutDlg)
    //}}AFX_DATA_MAP
    }BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    //{{AFX_MSG_MAP(CAboutDlg)
    // No message handlers
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
    // CTestDlg dialogCTestDlg::CTestDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CTestDlg::IDD, pParent)
    {
    //{{AFX_DATA_INIT(CTestDlg)
    // NOTE: the ClassWizard will add member initialization here
    //}}AFX_DATA_INIT
    // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }void CTestDlg::DoDataExchange(CDataExchange* pDX)
    {
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CTestDlg)
    // NOTE: the ClassWizard will add DDX and DDV calls here
    //}}AFX_DATA_MAP
    }BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
    //{{AFX_MSG_MAP(CTestDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
    // CTestDlg message handlersBOOL CTestDlg::OnInitDialog()
    {
    CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
    CString strAboutMenu;
    strAboutMenu.LoadString(IDS_ABOUTBOX);
    if (!strAboutMenu.IsEmpty())
    {
    pSysMenu->AppendMenu(MF_SEPARATOR);
    pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    }
    } // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE); // Set big icon
    SetIcon(m_hIcon, FALSE); // Set small icon
    pThread = AfxBeginThread( (AFX_THREADPROC)ListenerProcess,
    NULL,
    THREAD_PRIORITY_NORMAL,
    0,
    0,
    NULL);
    hEvent = CreateEvent(NULL,TRUE,TRUE,NULL);
    // TODO: Add extra initialization here

    return TRUE;  // return TRUE  unless you set the focus to a control
    }void CTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
    CAboutDlg dlgAbout;
    dlgAbout.DoModal();
    }
    else
    {
    CDialog::OnSysCommand(nID, lParam);
    }
    }// If you add a minimize button to your dialog, you will need the code below
    //  to draw the icon.  For MFC applications using the document/view model,
    //  this is automatically done for you by the framework.void CTestDlg::OnPaint() 
    {
    if (IsIconic())
    {
    CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle
    int cxIcon = GetSystemMetrics(SM_CXICON);
    int cyIcon = GetSystemMetrics(SM_CYICON);
    CRect rect;
    GetClientRect(&rect);
    int x = (rect.Width() - cxIcon + 1) / 2;
    int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon
    dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
    CDialog::OnPaint();
    }
    }// The system calls this to obtain the cursor to display while the user drags
    //  the minimized window.
    HCURSOR CTestDlg::OnQueryDragIcon()
    {
    return (HCURSOR) m_hIcon;
    }void CTestDlg::OnButton1() 
    {
    pause = 1;        
        if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)    
        {        
    a = 2;    

    pause = 0;
    }
      

  6.   

    OnButton1() 中先 suspend thread完了再 resume thread
      

  7.   

    先去掉 pause 看看 OnButton1 函数里面 if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)         
    {     
    a=2;        
    }   当点下函数时,没有修改事件信号状态!再看 ListenerProcess 函数 void ListenerProcess(LPVOID lpParameter)    //用于监听文件夹中是否有新文件需要更新 
    {     
    while(bTrun)          
    {       // 由于时间信号没修改,虽然a变成2,但是会马上通过下面if语句将a改回 1 if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)              
    {                     
    a = 1;             }  adddata();    // 由于 a 被改回 1 ,这里当然是老样子

    }              
    ExitThread(0);  

      

  8.   

    因此,adddata()函数里设置  ResetEvent(hEvent) 成了马后炮,因为 a 还是 1;不妨做下面修改
    // 点击按钮
    void CTest4Dlg::OnBnClickedButton2()
    {
    // TODO: 在此添加控件通知处理程序代码  if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)         
    {     

     ResetEvent(hEvent);  // 将线程暂停在 waitForSingleObjectEvent 语句
    a=2;        
                     // 把 adddata()的事情放到这里 
    ::MessageBox(NULL,L"进入了",L"进入了",MB_OK);
            
     SetEvent(hEvent);   // 恢复线程
    }  

    }同时 在 线程里 去掉 adddata()函数