MFC-线程同步

线程同步有四种方法.

两个简单的线程函数例子:

UINT Thread1(LPVOID lParam)
{
    for (int i = 0; i < 10000000;i++)
    {
      sum++;
    }
    SetDlgItemInt(AfxGetApp()->m_pMainWnd->m_hWnd, IDC_STATIC,sum,TRUE);
    return 0;
}
UINT Thread2(LPVOID lParam)
{
    for (int i = 0; i < 10000000; i++)
    {
        sum++;
    }
    SetDlgItemInt(AfxGetApp()->m_pMainWnd->m_hWnd, IDC_STATIC, sum, TRUE);
    return 0;
}

方法一:使用临界区对象(CCriticalSection类)
1.在构造函数中创建一个临界区对象

g_critical_section = new CCriticalSection();

2.分别给两个(或多个)线程加锁

for (int i = 0; i < 10000000;i++)
    {
        //加锁
        g_critical_section->Lock();
        sum++; //当操作共享数据时为了防止同时被操作导致结果错误,
               //所以要加锁,这个时候其它线程就不能对这个加锁的数据进程操作,需要等到这个数据解锁才能进程操作
        //解锁
        g_critical_section->Unlock();
    }

3.在析构函数中释放临界区对象

    delete g_critical_section;
    g_critical_section = nullptr;

这个同步方法相对于其它三种方法是最快的

方法二:使用互斥对象(CMutex类)

1.在构造函数中创建互斥对象

g_mutex = new CMutex();

2.分别给两个(或多个)线程加锁

//利用互斥对象作为参数,创建一个信号锁
    CSingleLock singlelock(g_mutex);
    for (int i = 0; i < 1000000; i++)
    {
        //加锁
        singlelock.Lock();
        //可能加锁失败,要判断是否加锁成功
        if (singlelock.IsLocked())
        {
            sum++; //当操作共享数据时为了防止同时被操作导致结果错误,
                   //所以要加锁,这个时候其它线程就不能对这个加锁的数据进程操作,需要等到这个数据解锁才能进程操作
                   //解锁
            singlelock.Unlock();
        }

    }

3.在析构函数中释放互斥对象

    delete g_mutex;
    g_mutex = nullptr;

这个方法比方法一慢了许多

方法三:使用信号量对象(CSemaphore类)

信号量是CSemaphore的对象,该对象的作用是对访问某个共享资源的线程的数目进行控制。
CSemaphore类的构造函数原型如下:

CSemaphore( 
    LONG lInitialCount /* = 1 */,    //计数器的初始值 
    LONG lMaxCount /* = 1 */,        //计数器的最大计数值 
    LPCTSTR pstrName/* =NULL */,        //信号的名称 
    LPSECURITY_ATTRIBUTES lpsaAttributes /* = NULL */    //指向一个SECURITY_ATTRIBUTES结构的指针 
) 

1.在构造函数中创建信号量对象

    //因为这个例子只有2个线程,所以计数器只要一个就行
    g_semaphore = new CSemaphore(1,1);

2.分别给两个(或多个)线程加锁

//利用信号量对象作为参数,创建一个信号锁
    CSingleLock singlelock(g_semaphore);
    for (int i = 0; i < 1000000; i++)
    {
        //加锁
        singlelock.Lock();
        //可能加锁失败,要判断是否加锁成功
        if (singlelock.IsLocked())
        {
            sum++; //当操作共享数据时为了防止同时被操作导致结果错误,
                   //所以要加锁,这个时候其它线程就不能对这个加锁的数据进程操作,需要等到这个数据解锁才能进程操作
                   //解锁
            singlelock.Unlock();
        }

    }

3.在析构函数中释放信号量对象

    delete g_semaphore;
    g_semaphore = nullptr;

方法4:使用事件对象(CEvent类)

1.在构造函数创建事件对象

g_event = new CEvent(TRUE);

2.分别给两个(或多个)线程加锁

//利用事件对象作为参数,创建一个信号锁
    CSingleLock singlelock(g_event);
    for (int i = 0; i < 1000000; i++)
    {
        //加锁
        singlelock.Lock();
        //可能加锁失败,要判断是否加锁成功
        if (singlelock.IsLocked())
        {
            sum++; //当操作共享数据时为了防止同时被操作导致结果错误,
                   //所以要加锁,这个时候其它线程就不能对这个加锁的数据进程操作,需要等到这个数据解锁才能进程操作
                   //解锁
            singlelock.Unlock();
            g_event->SetEvent();//必须要告诉其它线程本线程已经解锁,你可以加锁了
        }

    }

你可能感兴趣的:(线程同步,mfc,互斥对象,临界区对象,信号量对象)