首先我们假设一种情况 创建了10个线程 这些线程都执行一个线程函数 (都做一个事)
如 我们设置了是个窗口 每个窗口都负责买火车票 我们的火车票的总数为100
卖完为止
我们定义了一个全局变量
long ticket=100; 为票数
每卖出一张票 票数--
这里我们需要创建了10个线程 这些线程都执行一个线程函数 (买票)
但是 在多个线程同时访问一个共享资源时 会产生并发问题
如: 多个线程同时卖同一张票
那么为了解决并发问题 我么的
解决方案:线程同步
线程同步方式:
1.原子访问:同一时间 只允许一个线程访问资源 volatile防止编译优化,对特殊地址的稳定访问. 直接对内存进行操作
这里想对票数-- 可以用
InterlockedDecrement(&ticket); 他会对票数-- 直接对内存进行操作
同时避免进程并行问题
CRITICAL_SECTION m_cs;
2.临界区(关键段)(用户模式下的线程同步 ):同一时刻只允许一个进程访问代码段
分为:
(1)直接阻塞:如果已经有线程在执行代码段 他就会等待 直到那个线程执行完代码后 锁会随机分配给一个等待的进程
主函数中:
- //初始化关键段
- //InitializeCriticalSection(&m_cs);
线程函数中:
- EnterCriticalSection(&m_cs);
- if(ticket==0)
- {
- printf("Thread id[%d] go-------\n",GetCurrentThreadId());
-
-
-
-
-
- LeaveCriticalSection(&m_cs);
-
- break;
- }
- ticket--;
- printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);
-
- 锁的出口
- LeaveCriticalSection(&m_cs);
-
(2)旋转锁:如果已经有线程在执行代码段 他会等待一定的时间(由我们自己决定) 如果等待时间到了 代码段其他线程还是 没执行完 他就会走 不继续等待
这里不好测试 不直观 就不进行演示
(3)非阻塞:如果已经有线程在执行代码段 他就会走 不继续等待
主函数中:
- //初始化关键段
- //InitializeCriticalSection(&m_cs);
线程函数中:
- while(1)
- {
- if(ticket==0)
- {
- printf("Thread id[%d] go\n",GetCurrentThreadId());
- break;
-
- }
-
- Sleep(10);
-
-
-
-
- if(!TryEnterCriticalSection(&m_cs))
- continue;//走开
-
-
- //EnterCriticalSection(&m_cs);
-
-
-
-
- if(ticket==0)
- {
- printf("Thread id[%d] go-------\n",GetCurrentThreadId());
-
-
-
-
-
- LeaveCriticalSection(&m_cs);
-
- break;
- }
- ticket--;
- printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);
-
-
- LeaveCriticalSection(&m_cs);
-
-
-
- }
- return 0;
线程函数完整代码如下
- DWORD WINAPI ThreadProc(LPVOID lpParameter)
- {
- while(1)
- {
- if(ticket==0)
- {
- printf("Thread id[%d] go\n",GetCurrentThreadId());
- break;
-
- }
-
- Sleep(10);
-
-
- //原子访问
- //InterlockedDecrement(&ticket);//对共享资源执行--操作
-
- //锁的入口 只允许一个进程访问下列关键段
-
- //if(!TryEnterCriticalSection(&m_cs))//
- //continue;//走开
-
-
- //EnterCriticalSection(&m_cs);
-
- //事件的判断 看有没有信号 没信号就走
- if(WAIT_TIMEOUT==WaitForSingleObject(m_hSemaphore,10))
-
- {
- continue;
-
- }
-
-
-
- //WaitForSingleObject(m_hMutex,INFINITE);
- if(ticket==0)
- {
- printf("Thread id[%d] go-------\n",GetCurrentThreadId());
-
-
- //SetEvent(m_hEvent);
-
- //ReleaseMutex(m_hMutex);
- //LeaveCriticalSection(&m_cs);
- ReleaseSemaphore(m_hSemaphore,1,NULL);
- break;
- }
- ticket--;
- printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);
-
- //锁的出口
- //LeaveCriticalSection(&m_cs);
-
- //信号量
- ReleaseSemaphore(m_hSemaphore,1,NULL);
-
- //事件
- //SetEvent(m_hEvent);
-
- //互斥量
- //ReleaseMutex(m_hMutex);
-
- }
- return 0;
-
- }
3.内核对象:同一时刻只允许一个线程访问代码段
(1)互斥量:一直等互斥量 直到等到为止 执行代码
- //初始化互斥量
- //m_hMutex=CreateMutex(0,//安全属性
- // 1,//初始拥有权
- // L"MyMutex"//名字
- // );
- //ReleaseMutex(m_hMutex);
- DWORD WINAPI ThreadProc(LPVOID lpParameter)
- {
- while(1)
- {
- if(ticket==0)
- {
- printf("Thread id[%d] go\n",GetCurrentThreadId());
- break;
-
- }
-
- Sleep(10);
-
-
-
-
-
- WaitForSingleObject(m_hMutex,INFINITE);
- if(ticket==0)
- {
- printf("Thread id[%d] go-------\n",GetCurrentThreadId());
-
-
-
-
- ReleaseMutex(m_hMutex);
-
- break;
- }
- ticket--;
- printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);
-
-
- //互斥量
- ReleaseMutex(m_hMutex);
-
- }
- return 0;
-
- }
(2)事件 分配事件信号 谁 抢到谁执行
- //初始化事件
- //m_hEvent=CreateEventA(0,0,0,0);
- //SetEvent(m_hEvent);//初始信号为0 把信号设置为1 让线程去抢
- while(1)
- {
- if(ticket==0)
- {
- printf("Thread id[%d] go\n",GetCurrentThreadId());
- break;
-
- }
-
- Sleep(10);
-
-
-
- //事件的判断 看有没有信号 没信号就走
- if(WAIT_TIMEOUT==WaitForSingleObject(m_hEvent,10))
-
- {
- continue;
-
- }
-
-
-
-
- if(ticket==0)
- {
- printf("Thread id[%d] go-------\n",GetCurrentThreadId());
-
-
- SetEvent(m_hEvent);
-
-
- break;
- }
- ticket--;
- printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);
-
-
- //事件
- SetEvent(m_hEvent);
-
-
- }
- return 0;
(3)信号量:允许同一时间内指定数量的线程访问代码段
- //初始化信号量
- m_hSemaphore=CreateSemaphoreW(0,//安全属性
- 1,//初始化信号量总数
- 10,//最大信号量总数
- 0//名字
- );
- DWORD WINAPI ThreadProc(LPVOID lpParameter)
- {
- while(1)
- {
- if(ticket==0)
- {
- printf("Thread id[%d] go\n",GetCurrentThreadId());
- break;
-
- }
-
- Sleep(10);
-
-
-
-
-
-
-
- //信号的判断 看有没有信号 没信号就走
- if(WAIT_TIMEOUT==WaitForSingleObject(m_hSemaphore,10))
-
- {
- continue;
-
- }
-
-
-
-
- if(ticket==0)
- {
- printf("Thread id[%d] go-------\n",GetCurrentThreadId());
-
-
-
- ReleaseSemaphore(m_hSemaphore,1,NULL);
- break;
- }
- ticket--;
- printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);
-
-
- //信号量
- ReleaseSemaphore(m_hSemaphore,1,NULL);
-
-
-
- }
- return 0;
-
- }
上述三种内核对象需要在最后句柄释放
- if(m_hMutex)
- {
- CloseHandle(m_hMutex);
- m_hMutex=0;
- }
- if(m_hEvent)
- {
- CloseHandle(m_hEvent);
- m_hEvent=0;
- }
- if(m_hSemaphore)
- {
- CloseHandle(m_hSemaphore);
- m_hSemaphore=0;
- }
我们在这里实现了单例模式
- //单例
- HANDLE hdl=OpenMutexW(MUTEX_ALL_ACCESS,0,L"MyMutex");
- if(hdl)
- {
- qDebug()<<"app is exists";
- exit(0);
- }
完整代码如下
- #include
- #include
- #include
-
- long ticket=100;
- CRITICAL_SECTION m_cs;// 临街
- HANDLE m_hMutex;//互斥量
- HANDLE m_hEvent;//事件
- HANDLE m_hSemaphore;//信号量
-
- DWORD WINAPI ThreadProc(LPVOID lpParameter)
- {
- while(1)
- {
- if(ticket==0)
- {
- printf("Thread id[%d] go\n",GetCurrentThreadId());
- break;
-
- }
-
- Sleep(10);
-
-
- //原子访问
- //InterlockedDecrement(&ticket);//对共享资源执行--操作
-
- //锁的入口 只允许一个进程访问下列关键段
-
- //if(!TryEnterCriticalSection(&m_cs))//
- //continue;//走开
-
-
- //EnterCriticalSection(&m_cs);
-
- //事件的判断 看有没有信号 没信号就走
- if(WAIT_TIMEOUT==WaitForSingleObject(m_hSemaphore,10))
-
- {
- continue;
-
- }
-
-
-
- //WaitForSingleObject(m_hMutex,INFINITE);
- if(ticket==0)
- {
- printf("Thread id[%d] go-------\n",GetCurrentThreadId());
-
-
- //SetEvent(m_hEvent);
-
- //ReleaseMutex(m_hMutex);
- //LeaveCriticalSection(&m_cs);
- ReleaseSemaphore(m_hSemaphore,1,NULL);
- break;
- }
- ticket--;
- printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);
-
- //锁的出口
- //LeaveCriticalSection(&m_cs);
-
- //信号量
- ReleaseSemaphore(m_hSemaphore,1,NULL);
-
- //事件
- //SetEvent(m_hEvent);
-
- //互斥量
- //ReleaseMutex(m_hMutex);
-
- }
- return 0;
-
- }
- int main(int argc, char *argv[])
- {
- QCoreApplication a(argc, argv);
-
- //单例
- HANDLE hdl=OpenMutexW(MUTEX_ALL_ACCESS,0,L"MyMutex");
- if(hdl)
- {
- qDebug()<<"app is exists";
- exit(0);
- }
-
- //初始化信号量
- m_hSemaphore=CreateSemaphoreW(0,//安全属性
- 1,//初始化信号量总数
- 10,//最大信号量总数
- 0//名字
- );
-
-
- //初始化事件
- //m_hEvent=CreateEventA(0,0,0,0);
- //SetEvent(m_hEvent);//初始信号为0 把信号设置为1 让线程去抢
-
-
- //初始化关键段
- //InitializeCriticalSection(&m_cs);
-
-
- //初始化互斥量
- //m_hMutex=CreateMutex(0,//安全属性
- // 1,//初始拥有权
- // L"MyMutex"//名字
- // );
- //ReleaseMutex(m_hMutex);
-
-
- HANDLE han=NULL;
- for(int i=0;i<10;i++)
- {
- han=CreateThread(0,0,&ThreadProc,0,0,0);
- if(han)
- {
- CloseHandle(han);
- han=0;
-
- }
- }
-
-
- a.exec();
- //销毁关键段
- //DeleteCriticalSection(&m_cs);
-
- //释放内核对象 互斥量/事件
- if(m_hMutex)
- {
- CloseHandle(m_hMutex);
- m_hMutex=0;
- }
- if(m_hEvent)
- {
- CloseHandle(m_hEvent);
- m_hEvent=0;
- }
- if(m_hSemaphore)
- {
- CloseHandle(m_hSemaphore);
- m_hSemaphore=0;
- }
- return a.exec();
- }