zoukankan      html  css  js  c++  java
  • 线程同步

    今天要写的小程序是卖票

    结果如下:共100张票,10个线程

    需要声明的一些变量:

    public:
        volatile int m_tickets;//原子访问
         static unsigned __stdcall  ThreadProc(void* lparam);
         CListBox m_lstbox;
         map<unsigned int , int> IDMap;//将线程ID和0~10对应
         bool m_flag;
         CRITICAL_SECTION  m_cs;//临界区
         HANDLE m_Mutex;//互斥量

    按钮的处理函数:

    void CSoldTicketDlg::OnBnClickedButton1()
    {
        unsigned int IDnum;
        for(int i = 0; i < 10; i++)
        {
            _beginthreadex(NULL,0,&ThreadProc,this,0,&IDnum);
            IDMap[IDnum] = i;
        }
    }

     

    线程同步有两种:

     

    一 . 原子访问:指的是一个线程在访问某个资源的同时,能够保证没有其他线程会在同一时刻访问同一资源。Interlocked系列。

    volatile,:防止编译优化(从寄存器中取值,相对于从外存取值更节省时间,但造成了不能取到的值不能及时更新),对特殊地址的稳定访问。

    缺点:只能实现对一个32位或者64位值的单独访问,不能实现复杂的功能。

    二 . 关键段(临界区):同一时刻只一个线程访问代码段

    1.普通锁

    IniticalizeCriticalsection(&g_cs); //初始化CRITICAL_SECTION 中的成员变量

    EnterCriticalSection(&g_cs); //线程用它来检查占用标志的函数

    LeaveCriticalSection(&g_cs); //离开“卫生间”,门上重新置为无人

    DeleteCriticalsection(&g_cs); //删除事件的内核对象,以及为CRITICAL_SECTION初始化的资源。

    初始化函数:InitializeCriticalSection(&m_cs);

    在Destroy函数中:

    void CSoldTicketDlg::OnDestroy()
    {
        
        CDialogEx::OnDestroy();
        DeleteCriticalSection(&m_cs);
        
    }

    线程执行的函数:

     unsigned __stdcall  CSoldTicketDlg::ThreadProc(void* lparam)
     {
        CSoldTicketDlg* pthis = (CSoldTicketDlg*)lparam;
        int num = pthis->IDMap[GetCurrentThreadId()];
        while(1)
        {
            if(pthis->m_tickets <= 0 )
                break;
            Sleep(100);
            CString str;
             EnterCriticalSection(&pthis->m_cs);//锁住
            if(pthis->m_tickets > 0)//解决负数问题
            {
                str.Format(_T("第%d窗口,卖出第%d张票"),num , pthis->m_tickets--);
            } 
            LeaveCriticalSection(&pthis->m_cs);
            pthis->m_lstbox.AddString(str);
        }
        return 0;
    
     }

     

    2.旋转锁:

    InitializeCriticalSectionAndSpinCount:旋转锁不断循环,尝试在一段时间内获得访问权。只有当尝试失败的时候,线程才会切换到内核模式并进入等待状态。

    SetCriticalSectionSpinCount(   //改变旋转锁的次数

    在初始化函数中:InitializeCriticalSectionAndSpinCount(&m_cs,1);

    3.异步

    TryEnterCriticalSection:线程在访问时,如果不能访问资源,那么它继续做其他事情,而不用等待。

    将EnterCriticalSection换为

    if(!TryEnterCriticalSection(&pthis->m_cs))//异步
    continue;

    三 . 互斥量

    初始化函数:m_Mutex = CreateMutex(0,FALSE,0);//第二个参数为创建互斥量的进程没有优先级

     unsigned __stdcall  CSoldTicketDlg::ThreadProc(void* lparam)
     {
        CSoldTicketDlg* pthis = (CSoldTicketDlg*)lparam;
        int num = pthis->IDMap[GetCurrentThreadId()];
        while(1)
        {
            if(pthis->m_tickets <= 0 )
                break;
            Sleep(100);
            CString str;
            if(WAIT_TIMEOUT == WaitForSingleObject(pthis->m_Mutex,50))
                 continue;
            if(pthis->m_tickets > 0)//解决负数问题
            {
                str.Format(_T("第%d窗口,卖出第%d张票"),num , pthis->m_tickets--);
            } 
            ReleaseMutex(pthis->m_Mutex);
            pthis->m_lstbox.AddString(str);
        }
        return 0;
    
     }

     协同:

    四  .  事件

    五 . 信号量

    函数声明:

        CProgressCtrl m_a;
        CProgressCtrl m_b;
        CProgressCtrl m_c;
        CProgressCtrl* m_arr[3];
        static DWORD WINAPI ThreadProcA( LPVOID lpParameter);
        afx_msg void OnBnClickedButton1();
        afx_msg void OnBnClickedButton2();
        HANDLE m_semaphore;

    初始化:BOOL CRunDlg::OnInitDialog()

        m_a.SetStep(1);
        m_b.SetStep(5);
        m_arr[0] = &m_a;
        m_arr[1] = &m_b;
        m_arr[2] = &m_c;

    ready按钮:

    void CRunDlg::OnBnClickedButton1()
    {
        for(int i = 0; i < 3; i++)
        {
            CreateThread(0,0,&ThreadProcA,(LPVOID)i,0,0);
        }
    }

    go按钮:

    void CRunDlg::OnBnClickedButton2()
    {
        ReleaseSemaphore(m_semaphore,3,0);
    }

    线程执行函数:

     DWORD WINAPI CRunDlg::ThreadProcA( LPVOID lpParameter)
     {
         CRunDlg* pthis = (CRunDlg*)theApp.m_pMainWnd;
        int i = (int)lpParameter;
        WaitForSingleObject(pthis->m_semaphore ,INFINITE);
        while(1)
        {
            (pthis->m_arr[i])->StepIt();
            Sleep(100);
        }
     }
  • 相关阅读:
    Visual Studio插件CodeRush全新发布v20.1.5|支持运行设置文件
    DevExpress Data Access v20.1新版亮点:XPO
    VCL界面工具——DevExpress VCL v20.1.3全新发布
    你想要的WinForm界面开发教程在这里
    WPF界面开发技巧你知多少?Data Editors如何实现多选?
    Web开发实用技能,看Kendo UI for jQuery如何导出Excel(一)
    DevExpress XAF框架2020新改变!一篇文章带你看完
    Winforms界面开发新技能——Data Grid
    一招教你如何在WPF界面开发时自定义外观,快来Get!
    完整的jQuery UI组件库:Kendo UI for jQuery发布R2 2020 SP1
  • 原文地址:https://www.cnblogs.com/Lune-Qiu/p/8414652.html
Copyright © 2011-2022 走看看