线程同步
Posted Lune-Qiu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程同步相关的知识,希望对你有一定的参考价值。
今天要写的小程序是卖票
结果如下:共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);
}
}
以上是关于线程同步的主要内容,如果未能解决你的问题,请参考以下文章