• 线程同步


    今天要写的小程序是卖票

    结果如下:共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);
        }
     }
  • 相关阅读:
    Log4Net二次封装
    jquery动态生成二维码添加自定义logo
    小程序map地图多点定位
    vue上传阿里云图片组件
    vue移动端地址三级联动组件(二)
    vue移动端地址三级联动组件(一)
    vue自定义轻量级form表单校验
    js中间件
    事件模型
    通过JS唤醒app(安卓+ios)
  • 原文地址:https://www.cnblogs.com/Lune-Qiu/p/8414652.html
Copyright © 2020-2023  润新知