小弟在对话框中添加了四个成员变量:
CWinThread* thWriteD;
CWinThread* thWriteW;//线程指针
HANDLE handleW;
HANDLE handleD;//用于保存的线程句柄
再往类里添加了两个回调函数:
static UINT CALLBACK WriteW(LPVOID pParam);
static UINT CALLBACK WriteD(LPVOID pParam);
声明四个全局变量:
static volatile BOOL m_bCloseW;//标识线程退出
static volatile BOOL m_bCloseD;static CCriticalSection m_Section;//临界区对象
static TCHAR szSema[10];然后添加两个按钮用于启动线程:
void CMySemaphoreDlg::OnWriteD()
{
m_bCloseD=false;
    thWriteD=AfxBeginThread((AFX_THREADPROC)WriteD,&m_Edit,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);
handleD=thWriteD->m_hThread;
thWriteD->ResumeThread();


}void CMySemaphoreDlg::OnWriteW()
{
m_bCloseW=false;
thWriteW=AfxBeginThread((AFX_THREADPROC)WriteW,&m_Edit,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);
handleW=thWriteW->m_hThread;

thWriteW->ResumeThread();

}以下是回调函数体:
UINT CMySemaphoreDlg::WriteD(LPVOID pParam)
{
     CEdit* m_pEdit=(CEdit*)pParam;
 m_pEdit->SetWindowText(_T(""));
 m_Section.Lock();
 for (int i=0;i<10;i++)
 {
 if(!m_bCloseD)
 {
 szSema[i]=_T('D');
 m_pEdit->SetWindowText(szSema);
 ::Sleep(1000);
 }
 else
 {
 break;
 }
 }
 m_Section.Unlock();
 return 0;
}UINT CMySemaphoreDlg::WriteW(LPVOID pParam)
{
CEdit* m_pEdit=(CEdit*)pParam;
m_pEdit->SetWindowText(_T(""));
m_Section.Lock();
for (int i=0;i<10;i++)
{
     if(!m_bCloseW)
 {
szSema[i]=_T('W');

m_pEdit->SetWindowText(szSema);
::Sleep(1000);
 }
 else
 {
            break;
 }

}
m_Section.Unlock();


return 0;
}
在析构函数中等待线程退出:
CMySemaphoreDlg::~CMySemaphoreDlg()
{


        m_bCloseD=false;
m_bCloseW=false; HANDLE handles[]={handleD,handleW};
WaitForMultipleObjects(2,handles,TRUE,INFINITE);

   

}
为什么当两个线程都启动时,就会报错呢,应该如何修改?

解决方案 »

  1.   

    我不知道你的错误信息
    看到你的代码分析:
    建议将m_Section.Lock();组合放到循环的里面贴出你的错误信息和所有的源码别人能给你调试
      

  2.   

    两个线程都是对同一个m_Edit对象,这样在"同时启动"两个线程启动时,执行到
      CEdit*   m_pEdit=(CEdit*)pParam; 
      m_pEdit-> SetWindowText(_T("")); 
    而这时还没有m_Section.Lock();
    同一时刻出现多个线程访问共享资源
      

  3.   

    1.那个WaitForMultipleObjects方法真的不太好用,每次退出时候,要计算出有多少个线程还活着,这个方法的第一个参数必须是动态的.
    2传递给WaitForMultipleObjects方法的句柄数组不能用线程指针来引用,必须事先保留起来.
    怪不得退出对话框出错,那个标志位没有设置成true,所以一运行到WaitForMultipleObjects就报错,现将正确的代码贴出来:
    头文件
     
    // CMyCtriticalSectionDlg 对话框
    class CMyCtriticalSectionDlg : public CDialog
    {
    // 构造
    public:
    CMyCtriticalSectionDlg(CWnd* pParent = NULL); // 标准构造函数
        ~CMyCtriticalSectionDlg();
    // 对话框数据
    enum { IDD = IDD_MYCTRITICALSECTION_DIALOG };
        CEdit m_Edit;

    protected:
    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
        CWinThread*   thWriteD; 
        CWinThread*   thWriteW;//线程指针 
        HANDLE   handleW; 
        HANDLE   handleD;//用于保存的线程句柄 
        // 实现
    protected:
    HICON m_hIcon;
        static   UINT   CALLBACK   WriteW(LPVOID   pParam); 
        static   UINT   CALLBACK   WriteD(LPVOID   pParam);  // 生成的消息映射函数
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg void OnWriteD();
    afx_msg void OnWriteW();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()
    };static  volatile BOOL m_bCloseW; //控制线程退出的标志
    static  volatile BOOL m_bCloseD; static CCriticalSection m_Section;//临界区对象
    static TCHAR szSema[10]; //输入的字符串
    cpp文件:
     
    #include "stdafx.h"
    #include "MyCtriticalSection.h"
    #include "MyCtriticalSectionDlg.h"#ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    // CMyCtriticalSectionDlg 对话框
    CMyCtriticalSectionDlg::CMyCtriticalSectionDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CMyCtriticalSectionDlg::IDD, pParent)
    {
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }CMyCtriticalSectionDlg::~CMyCtriticalSectionDlg()
    {
    m_bCloseD=true; 
            m_bCloseW=true; 
        
    HANDLE handles[2];
    int i=0;
            if(WaitForSingleObject(handleD,0)==WAIT_TIMEOUT)
    {
    handles[0]=handleD;
    i++;
    }
    if(WaitForSingleObject(handleW,0)==WAIT_TIMEOUT)
    {
    handles[1]=handleW;
    i++;
    }
            WaitForMultipleObjects(i,handles,TRUE,INFINITE); 
        }
    void CMyCtriticalSectionDlg::DoDataExchange(CDataExchange* pDX)
    {
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX,IDC_EDIT1,m_Edit);
    }BEGIN_MESSAGE_MAP(CMyCtriticalSectionDlg, CDialog)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_COMMAND(IDC_WRITEW,&CMyCtriticalSectionDlg::OnWriteW)
    ON_COMMAND(IDC_WRITED,&CMyCtriticalSectionDlg::OnWriteD)
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    // CMyCtriticalSectionDlg 消息处理程序
    void CMyCtriticalSectionDlg::OnWriteD()
    {
        m_bCloseD=false; 
        thWriteD=AfxBeginThread((AFX_THREADPROC) WriteD,&m_Edit,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL); 
        handleD=thWriteD-> m_hThread; 
        thWriteD-> ResumeThread(); 

    }void CMyCtriticalSectionDlg::OnWriteW()
    {
        m_bCloseW=false; 
        thWriteW=AfxBeginThread((AFX_THREADPROC)WriteW,&m_Edit,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL); 
        handleW=thWriteW-> m_hThread;     thWriteW-> ResumeThread(); 
      }
    UINT   CMyCtriticalSectionDlg::WriteD(LPVOID   pParam) 

      CEdit*   m_pEdit=(CEdit*)pParam; 
      m_pEdit-> SetWindowText(_T("")); 
      m_Section.Lock(); 
      for   (int   i=0;i <10;i++) 
      { 
         if(!m_bCloseD) 
         { 
            szSema[i]=_T('D'); 
            m_pEdit-> SetWindowText(szSema); 
            ::Sleep(1000); 
         } 
         else 
         { 
             break; 
         } 
      } 
      m_Section.Unlock(); 
     
      return   0; 
    } UINT   CMyCtriticalSectionDlg::WriteW(LPVOID   pParam) 

      CEdit*   m_pEdit=(CEdit*)pParam; 
      m_pEdit-> SetWindowText(_T("")); 
      m_Section.Lock(); 
      for (int   i=0;i <10;i++) 
      { 
          if(!m_bCloseW) 
          { 
              szSema[i]=_T('W');           m_pEdit-> SetWindowText(szSema); 
              ::Sleep(1000); 
          } 
          else 
          { 
              break; 
          }
       } 
       m_Section.Unlock(); 
       return   0; 

    BOOL CMyCtriticalSectionDlg::OnInitDialog()
    {
    CDialog::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。
    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);
    }
    } // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE); // 设置大图标
    SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
    }void CMyCtriticalSectionDlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
    CAboutDlg dlgAbout;
    dlgAbout.DoModal();
    }
    else
    {
    CDialog::OnSysCommand(nID, lParam);
    }
    }// 如果向对话框添加最小化按钮,则需要下面的代码
    //  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
    //  这将由框架自动完成。void CMyCtriticalSectionDlg::OnPaint()
    {
    if (IsIconic())
    {
    CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作矩形中居中
    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; // 绘制图标
    dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
    CDialog::OnPaint();
    }
    }//当用户拖动最小化窗口时系统调用此函数取得光标显示。
    //
    HCURSOR CMyCtriticalSectionDlg::OnQueryDragIcon()
    {
    return static_cast<HCURSOR>(m_hIcon);
    }