大连网站制作培训,深圳企业网站制作推广运营,先网站开发后软件开发好,wordpress主题美化插件目录
1. 用户模式(User mode)和内核模式(Kernal mode)
2. 用户模式的同步(CRITICAL_SECTION)
3. 内核模式同步
3.1 互斥量
3.2 信号量
3.3 事件对象
4. 实现Windows平台的多线程服务器端 1. 用户模式(User mode)和内核模式(Kernal mode)
Windows操作系统的运行方式是“…目录
1. 用户模式(User mode)和内核模式(Kernal mode)
2. 用户模式的同步(CRITICAL_SECTION)
3. 内核模式同步
3.1 互斥量
3.2 信号量
3.3 事件对象
4. 实现Windows平台的多线程服务器端 1. 用户模式(User mode)和内核模式(Kernal mode)
Windows操作系统的运行方式是“双模式操作”
用户模式运行应用程序的基本模式禁止访问物理设备而且会限制访问的内存区域。内核模式操作系统运行时的模式不仅不会限制访问的内存区域而且访问的硬件设备也不会受损。
在应用程序的运行过程中Windows操作系统会在用户模式和内核模式之间切换。比如说在Windows中创建线程虽然创造线程的请求是由应用程序的函数调用来完成的但是线程是属于操作系统的所以Windows会先从用户模式切换到内核模式接着创建线程分配资源创建内核对象。 为什么要定义这两种模式 答为了提高安全性。因为应用程序在运行时如果发生错误就可能会破坏操作系统的各种资源。尤其是C/C可以进行指针运算就很容易发生这种问题。而用户模式可以保护与操作系统有关的内存区域。所以应用程序在运行时发生错误也只会终止应用程序的运行而不会终止操作系统。 那这两种模式只有优点吗 答不是频繁的模式切换对系统而言也是一种负担会影响性能。 2. 用户模式的同步(CRITICAL_SECTION)
用户模式的同步是在用户模式下的同步这意味着无需操作系统的帮助而在应用程序级别进行的同步 即无需进行内核模式的切换。 优点速度快。 缺点功能上存在局限性。
创建CRITICAL_SECTION对象
#includewindows.hvoid InitializeCriticalSection(
LPCRITICAL_SECTION lpCriticalSection //传入需要初始化的CRITICAL_SECTION对象//的地址值
);
CRITICAL_SECTION对象不是内核对象。其只是一把进入临界区的“钥匙”。要进入临界区就提供这一把钥匙离开临界区就要上交钥匙。
“销毁”CRITICAL_SECTION对象
#includewindows.hvoid DeleteCriticalSection(
LPCRITICAL_SECTION lpCriticalSection //传入需要销毁的CRITICAL_SECTION对象//的地址值
);
实际上这个函数并不是销毁CRITICAL_SECTION对象而是销毁CRITICAL_SECTION对象使用过的(或与其相关的)资源。
上锁
#includewindows.hvoid EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
解锁
#includewindows.hvoid LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
3. 内核模式同步
内核模式的同步就是在内核模式下的同步。意味着都是通过操作系统的帮助下进行的线程同步。可以实现跨进程之间进行线程同步。因为内核对象属于操作系统而不属于进程
优点比用户模式提供的功能更多、可以指定超时防止产生死锁缺点速度相对用户模式来说较慢
3.1 互斥量
互斥量对象是auto-reset模式的内核对象。([C 网络协议] Windows平台下的线程里有解释
创建互斥量
#includewindows.hHANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, //传递安全相关的配置信息传NULL使用默认安全配置
BOOL bInitialOwner, //TRUE创建的互斥量属于调用该函数的线程//同时进入non-signaled状态//FALSE创建处的互斥量对象不属于任何线程//同时进入signaled状态
LPCTSTR lpName //用于命名互斥量对象传NULL表示无名
);
成功返回创建的互斥量对象句柄
失败返回NULL
bInitialOwner参数其实就是初始化互斥量的状态的值为TRUE初始化为non-signaled状态。为FALSE初始化为signaled状态。
销毁互斥量
#includewindows.hBOOL CloseHandle(HANDLE hObject);
成功返回TRUE
失败返回FALSE
获取互斥量(上锁)
#includewindows.hDWORD WaitForSingleObject(
HANDLE hHandle, //查看状态的内核对象句柄
DWORD dwMilliseconds //以1/1000秒为单位指定超时时间传递INFINITE会阻塞住//直到内核对象变为signaled状态
);
成功返回事件信息事件信息成功进入signaled状态返回WAIT_OBJECT_0,超时返回WAIT_TIMEOUT
失败返回WAIT_FAILED
这个函数就是“单个内核对象状态的查看”。所以可以判断出线程是否被阻塞看的是互斥量内核对象的状态。
释放互斥量(解锁)
#includewindows.hBOOL ReleaseMutex(HANDLE hMutex);
成功返回TRUE并使互斥量重新进入signaled状态
失败返回FALSE
例
HANDLE mutex;
int main()
{mutexCreateMutex(NULL,FALSE,NULL); //mutex初始化为signaled状态......
}unsigned WINAPI threadOne(void* arg)
{WaitForSingleObject(mutex,INFINITE); //mutex为signaled状态则继续执行//临界区开始 //因为mutex是auto-reset模式的内核对象所以mutex会变为non-signaled状态...... //临界区结束ReleaseMutex(mutex); //释放mutex将其设置为signaled状态
}unsigned WINAPI threadTwo(void* arg)
{WaitForSingleObject(mutex,INFINITE); //因为上面线程先执行mutex变为了non-signaled状态所以线程阻塞住等待mutex的释放//临界区开始......//临界区结束ReleaseMutex(mutex);
}
3.2 信号量
创建信号量
#includewindows.hHANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, //安全配置信息默认安全设置传递NULL
LONG lInitialCount, //指定信号量的初始值应0且lMaximumCount
LONG lMaximumCount, //信号量的最大值为1则是二进制信号量(只能表示0或1)
LPCTSTR lpName //命名信号量对象传NULL为无名
);
成功返回创建的信号量对象的句柄
失败返回NULL
销毁信号量和互斥量是一样的销毁句柄语句
#includewindows.hBOOL CloseHandle(HANDLE hObject);
成功返回TRUE
失败返回FALSE
通过信号量判断线程是否阻塞
#includewindows.hDWORD WaitForSingleObject(
HANDLE hHandle, //查看状态的内核对象句柄
DWORD dwMilliseconds //以1/1000秒为单位指定超时时间传递INFINITE会阻塞住//直到内核对象变为signaled状态
);
成功返回事件信息事件信息成功进入signaled状态返回WAIT_OBJECT_0,超时返回WAIT_TIMEOUT
失败返回WAIT_FAILED
这个函数也是“单个内核对象状态的查看”。返回的同时信号量-1。
利用信号量为0时进入non-signaled状态大于0时进入signaled状态来进行同步。
释放信号量
#includewindows.hBOOL ReleaseSemaphore(
HANDLE hSemaphore, //传递需要释放的信号量
LONG lReleaseCount, //释放信号量会增加这个参数指定要增加的值超过最大值则不增加且返回FALSE
LPLONG lpPreviousCount //保存修改之前值得变量地址不需要的话可传NULL
);
成功返回TRUE
失败返回FALSE
例
HANDLE semOne;
HANDLE semTwo;int main()
{semOneCreateSemaphore(NULL,0,1,NULL); //semOne为non-signaled状态semTwoCreateSemaphore(NULL,1,1,NULL); //semTwo为signaled状态......
}unsigned WINAPI threadOne(void* arg)
{WaitForSingleObject(semTwo,INFINITE); //semTwo为signaled状态继续执行且semTwo-1变为non-signaled状态//临界区......//临界区ReleaseSemaphore(semOne,1,NULL); //semOne1变为signaled状态
}unsigned WINAPI threadTwo(void* arg)
{WaitForSingleObject(semOne,INFINITE); //通过上一个线程semOne为signaled状态开始执行且semOne-1变为non-signaled状态//临界区......//临界区ReleaseSemaphore(semTwo,1,NULL);
}
3.3 事件对象
基于事件对象的线程同步与前两种同步方式有很大不同因为事件对象创建时可以选择是“auto-reset”模式还是“manual-reset”模式。这也是其进行同步的方式。
创建事件对象
#includewindows.hHANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, //安全配置信息默认安全设置传递NULL
BOOL bManualReset, //TRUE创建manual-reset模式的事件对象//FALSE创建auto-reset模式的事件对象
BOOL bInitialState, //TRUE,事件对象初始化为signaled状态//FALSE,事件对象初始化为non-signaled状态
LPCTSTR lpName //命名信号量对象传NULL为无名
);
成功返回创建的事件对象句柄
失败返回NULL
销毁事件对象(销毁句柄语句)
#includewindows.hBOOL CloseHandle(HANDLE hObject);
成功返回TRUE
失败返回FALSE
更改事件对象状态
#includewindows.hBOOL ResetEvent(HANDLE hEvent); //将事件对象设置为non-signaled状态
BOOL SetEvent(HANDLE hEvent); //将事件对象设置为signaled状态
成功返回TRUE
失败返回FALSE
例如实现两个线程同时退出阻塞状态的情景。
HANDLE event;int main()
{eventCreateEvent(NULL,TRUE,FALSE,NULL); //将事件对象设置为mamual-reset模式并初始化为non-signaled状态......SetEvent(event); //将事件对象设置为singnaled状态......
}unsigned WINAPI threadOne(void* arg)
{WaitForSingleObject(event,INFINITE); //阻塞等待事件对象设置为singaled状态//临界区......//临界区
}unsigned WINAPI threadTwo(void* arg)
{WaitForSingleObject(event,INFINITE); //阻塞等待事件对象设置为singaled状态//临界区......//临界区
}
4. 实现Windows平台的多线程服务器端