多线程
根据不同操作系统内核限制,硬件内存的限制等,线程的数量是有上限的。在操作系统中有两个资源会限制开子线程的个数。首先每个子线程有一个file descriptor(windows里面叫handle句柄)操作系统分给每个进程的fd个数有上限的。其次每个子线程会占用stack(栈),编译时,每个进程stack的大小是有限制的,编译选项可以设置stack的大小上限。当达到上限,就不可以在创建子线程。
EnterCriticalSection多线程的应用
当其它线程遇到EnterCriticalSection()语句,会将当前线程挂起,继续运行没有运行完的线程。当前线程运行到LeaveCriticalSection()时,其它线程才开始运行。
EnterCriticalSection(&m_CSLanguage);
// 操作dwTime
LeaveCriticalSection(&m_CSLanguage);
WaitForSingleObject函数用法
DWORD WaitForSingleObject(
HANDLE hObject, //指明一个内核对象的句柄
DWORD dwMilliseconds); //等待时间
该函数需要传递一个内核对象句柄,该句柄标识一个内核对象,如果该内核对象处于未通知状态,则该函数导致线程进入阻塞状态;如果该内核对象处于已通知状态,则该函数立即返回WAIT_OBJECT_0。第二个参数指明了需要等待的时间(毫秒),可以传递INFINITE指明要无限期等待下去,如果第二个参数为0,那么函数就测试同步对象的状态并立即返回。如果等待超时,该函数返回WAIT_TIMEOUT。如果该函数失败,返回WAIT_FAILED。可以通过下面的代码来判断:
Sleep()
Sleep延时也是阻塞线程的一种方式。
Sleep括号里的时间,在windows下是已毫秒为单位,而Linux是以秒为单位。
CreateEvent(NULL, FALSE, FALSE, NULL)
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // SD
BOOL bManualReset, // reset type
BOOL bInitialState, // initial state
LPCTSTR lpName // object name
);
lpEventAttributes:指向SECURITY_ATTRIBUTES结构体,此结构体决定函数的返回句柄是否可以让子进程继承。如果这个参数为NULL,这个句柄是不能继承的。一般情况下,这个参数设置为NULL。
bManualReset:指定将创建的EVENT是自动复位还是手动复位。如果为TRUE,需要用ResetEvent(HANDLE)函数手动复位状态为无信号,即一旦改EVENT被设置成有信号,则它会一直等到ResetEvent调用时才为无信号状态。如果为FALSE,当一个有信号的等待线程被释放后,系统会自动复位状态为无信号状态。
bInitialState:指定事件对象的初始状态。如果为TRUE,初始状态为有信号,否则为无信号。
lpName: 事件对象的名称,以字符串表示。名称的长度受MAX_PATH的限制,名称是大小写敏感的。如果lpName匹配一个存在的命名的事件对象,函数将请求EVENT_ALL_ACCESS来访问存在的对象。在这种情况下,bManualReset和bInitialState 被忽略,因为这两个参数已经被存在的事件设置。如果lpEventAttributes参数不为NULL,这个参数可以决定是否句柄被继承,但是它的安全描述(security-descriptor)成员被忽略。如果lpName 为NULL,创建一个没有名称的事件。如果lpName 匹配一个存在的semaphore, mutex, waitable timer, job或者file-mapping对象的名称,函数调用失败,GetLastError函数返回ERROR_INVALID_HANDLE。由于这些对象共享相同的命名空间,才导致这种情况的发生。