使用信号量内核对象进行线程同步主要会用到 CreateSemaphore()、OpenSemaphore()、ReleaseSemaphore()、 WaitForSingleObject()和WaitForMultipleObjects(),CloseHandle()关闭信号量等函数。其中,CreateSemaphore()用来 创建一个信号量内核对象,其函数原型为:
HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // 安全属性指针 LONG lInitialCount, // 初始计数 LONG lMaximumCount, // 最大计数 LPCTSTR lpName // 对象名指针 ); |
参数lMaximumCount是一个有符号32位值,定义了允许的最大资源计数,最大 取值不能超过4294967295。lpName参数可以为创建的信号量定义一个名字,由于其创建的是一个内核对象,因此在其他进程中可以通过该名字而得 到此信号量。OpenSemaphore()函数即可用来根据信号量名打开在其他进程中创建的信号量,函数原型如下:
HANDLE OpenSemaphore( DWORD dwDesiredAccess, // 访问标志 BOOL bInheritHandle, // 继承标志 LPCTSTR lpName // 信号量名 ); |
在线程离开对共享资源的处理时,必须通过ReleaseSemaphore()来增加当 前可用资源计数。否则将会出现当前正在处理共享资源的实际线程数并没有达到要限制的数值,而其他线程却因为当前可用资源计数为0而仍无法进入的情况。 ReleaseSemaphore()的函数原型为:
BOOL ReleaseSemaphore( HANDLE hSemaphore, // 信号量句柄 LONG lReleaseCount, // 计数递增数量 LPLONG lpPreviousCount // 先前计数 ); |
该函数将lReleaseCount中的值添加给信号量的当前资源计数,一般将 lReleaseCount设置为1,如果需要也可以设置其他的值。WaitForSingleObject()和 WaitForMultipleObjects()主要用在试图进入共享资源的线程函数入口处,主要用来判断信号量的当前可用资源计数是否允许本线程的进 入。只有在当前可用资源计数值大于0时,被监视的信号量内核对象才会得到通知。
信号量的使用特点使其更适用于对Socket(套接字)程序中线程的同步。例如,网络上的HTTP服务器要对同一时间内访问同一页面的用户数加以限 制,这时可以为没一个用户对服务器的页面请求设置一个线程,而页面则是待保护的共享资源,通过使用信号量对线程的同步作用可以确保在任一时刻无论有多少用 户对某一页面进行访问,只有不大于设定的最大用户数目的线程能够进行访问,而其他的访问企图则被挂起,只有在有用户退出对此页面的访问后才有可能进入。
- #include <iostream>
- #include <fstream>
- #include <windows.h>
- #include <process.h>
- using namespace std;
- void semaphoreTest(void *ptr)
- {
- int flag = *(int *)ptr;
- HANDLE semaphore = CreateSemaphore(NULL, 2, 2, (LPCWSTR)"streamSemaphore");
- WaitForSingleObject(semaphore, INFINITE);
- ofstream fileStream("c:/test.txt", ios_base::app);
- for (int i = 0; i < 5; ++i)
- {
- Sleep(1000);
- fileStream<<flag;
- fileStream<<' '<<flush;
- //cout<<flag<<' ';
- }
- fileStream.close();
- ReleaseSemaphore(semaphore, 1, NULL);
- CloseHandle(semaphore);
- }
- int main()
- {
- int flag[] = {1, 2, 3};
- for (int i = 0; i < 3; ++i)
- {
- _beginthread(semaphoreTest, 0, &flag[i]);
- }
- Sleep(INFINITE);
- }
linux下的信号量,实现多个线程,多资源的访问。
Windows下的信号量有一个最大值和一个初始值,初始值和最大值可以不同。 而且Windows下的信号量是一个【内核对象】,在整个OS都可以访问到。
Linux下的信号量在创建的时候可以指定一个初始值,这个初始值也是最大值。 而且Linux下的信号量可以根据需要设置为是否是【进程间共享】的,如果不是进程间共享的则就是一个本进程局部信号量。
int semt_init( semt_t* sem, //a semaphore pointer
int pshared, //0 as a local semaphore of cuurent process, or the semaphore can be shared between mulit processes
unsigned value //the init value of this memaphore
) //minus ONE value of semaphore
int sem_wait(sem_t* sem); //add ONE value of semaphore
int sem_post(sem_t* sem); //destroy the semaphore
int sem_destroy(sem_t* sem); All the functions above Rerurn ZERO IF SUCCESS !
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
using namespace std;
sem_t g_semt;
void* work_thread(void* p)
{
pthread_t tID = pthread_self();
cout << "-------" << tID << " is waiting for a semaphore -------" << endl;
sem_wait(&g_semt);
cout << "-------" << tID << " got a semaphore, is Runing -------" << endl << endl;
usleep(1000 * 1000 * 2); //2 seconds
sem_post(&g_semt);
static char* pRet = "thread finished! \n";
return pRet;
}
int main()
{
const size_t nThreadCount = 5; //amounts of thread array
const unsigned int nSemaphoreCount = 2; //initial value of semaphore
int nRet = -1;
void* pRet = NULL;
pthread_t threadIDs[nThreadCount] = {0};
nRet = sem_init(&g_semt, 0, nSemaphoreCount);
if (0 != nRet)
return -1;
for (size_t i = 0; i < nThreadCount; ++ i)
{
nRet = pthread_create(&threadIDs[i], NULL, work_thread, NULL);
if (0 != nRet)
continue;
}
for (size_t i = 0; i < nThreadCount; ++ i)
{
int nRet2 = pthread_join(threadIDs[i], &pRet);
cout << endl << threadIDs[i] << " return value is " << (char*)pRet << endl;
}
cout << endl << endl;
sem_destroy(&g_semt);
return 0;
}