多线程学习笔记

    技术2022-07-11  76

    一、摘要

    1.线程函数

    DWORD WINAPI threadname(LPVOID lpParamter) // 函数名字可随意 { int *a = (int *)lpParamter; return 0L; }

    2.创建线程

    HANDLE hThread = CreateThread(NULL, 0, threadname, NULL, 0, NULL);

    3.等待线程

    WaitForSingleObject(hThread , INFINITE);

    4.互斥量

    HANDLE cout_mutex; cout_mutex = CreateMutex(NULL, FALSE, NULL); WaitForSingleObject(cout_mutex, INFINITE); ReleaseMutex(cout_mutex);

    二、内容

    1. CreateThread()

    //返回值:一个HANDLE类型的值,表示线程的句柄,可用于等待线程等函数 HANDLE CreateThread(   LPSECURITY_ATTRIBUTES   lpThreadAttributes, // 不重要,一般设置为NULL   SIZE_T                  dwStackSize,        // 堆栈大小,不重要,一般设置为0,表示使用默认堆栈大小   LPTHREAD_START_ROUTINE  lpStartAddress,     // 函数指针,传入函数名或指针即可   __drv_aliasesMem LPVOID lpParameter,        // 参数指针,供函数使用   DWORD                   dwCreationFlags,    // 不重要,一般设置为0   LPDWORD                 lpThreadId          // 指针,用于保存线程的id,一般设置为NULL );]

    使用方法1:无参数多线程函数

    DWORD WINAPI threadname(LPVOID lpParamer) { //do something return 0L; } HANDLE hThread = CreateThread(NULL,0,threadname,NULL,0,MULL)

    使用方法2:有参多线程函数:lpParameter参数

      概念: 

     lpParamter 跟 void指针使用方法类似,void指针可以指向任何数据,所以我们可以把任何类形指针的值赋给void指针(但不能把void指针的值直接赋给其它类型的指针!)

    int a = 0;

    int *intp = &a;

    // int指针 转 void指针

    void * voidp = intp; // 合法!不会报错

    实例:

    DWORD WINAPI MyThread(LPVOID lpParamter) { // 把lpParamter当成void指针就完事儿了 int *a = (int *)lpParamter; cout << "I have " << a[0] << " dolors!\n"; return 0L; } //而创造函数时候,传入一个整形指针就行了 int main () { int a = 0; int *p = &a; // 创造线程,注意我把p指针作为参数传入了,它也就成为了上方函数的lpParamter CreateThread(NULL, 0, MyThread, p, 0, NULL); // 记得等待线程结束 system("PAUSE"); return 0; }

    至于传入更多的参数,可以自己设计一个struct或者class数据结构,并传入其指针就行了,或者也可以传入数组。 至于返回值,也可以利用传入的指针来接收。

    2.等待指定线程结束:WaitForSingleObject()

         (1)这个特别简单,此函数就两个参数,第一个参数是创建线程时可得到的返回值(HANDLE)也就是句柄,第二个参数不用关心,传入INFINITE就行了。

         (2)如果事件是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUT。

         (3)WaitForSingleObject函数用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。参数dwMilliseconds有两个具有特殊意义的值:0和INFINITE。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。  

    使用实例:

    //函数声明 DWORD WaitForSingleObject(HANDLE hHandle , DWORD dwMilliseconds); //参数1:可以传入句柄,监控线程;可以传入Event对象,控制线程运行状态; //参数2:0代表立即返回;INFINITE代表线程一直挂起;填入数值则超时退出 返回值        含义  WAIT_FAILED     函数失败  WAIT_OBJECT_0    指定的同步对象处于有信号的状态  WAIT_ABANDONED  拥有一个mutex的线程已经中断了,但未释放该MUTEX  WAIT_TIMEOUT    超时返回,并且同步对象无信号  HANDLE hThread = CreateThread(NULL, 0, thread1, NULL, 0, NULL); // 利用得到的句柄等待线程结束 WaitForSingleObject(hThread, INFINITE);

    有了这个函数,再也不用Sleep或者While(1)啦。

     

    3.多线程资源加锁:CreateMutex()

    1.概念

    (1)声明

    1.声明 HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全属性的指针 BOOL bInitialOwner, // 初始化互斥对象的所有者 LPCTSTR lpName // 指向互斥对象名的指针 ); 2.创建 //只是创建了一把锁, 到目前这句完成, 他没有锁任何东西。 HANDLE m_hMutex = CreateMutex(NULL,TRUE,"cplusplus_me"); 3.使用 //从线程函数开始加锁 ,到线程函数结束时解锁 //加锁 WaitForSingleObject(hMutex, INFINITE); //这里写被加锁的东西. 一般是操作一些共享数据(占用系统内存)。 //解锁 ReleaseMutex(hMutex);

    (2)调用

    HANDLE m_hMutex = CreateMutex(NULL,TRUE,"cplusplus_me");   只是创建了一把锁, 到目前这句完成, 他没有锁任何东西。

     

    2.为资源加锁:

     

    创建方法: // 声明一个句柄 HANDLE cout_mutex; // 创建一个锁 cout_mutex = CreateMutex(NULL, FALSE, NULL); 使用方法: // 等待其它线程释放锁,并获取锁的使用权 WaitForSingleObject(cout_mutex, INFINITE); // 获取锁之后,只要没有解锁,其它线程就会阻塞在WaitForSingleObject()语句。 做一些工作(使用需要互斥的资源等) // 解锁! ReleaseMutex(cout_mutex);

    使用例子:

    HANDLE cout_mutex; DWORD WINAPI MyThread(LPVOID lpParamter) { // 把lpParamter当成void指针就完事儿了 int *a = (int *)lpParamter; WaitForSingleObject(cout_mutex, INFINITE); cout << "I have " << a[0] << " dolors!" << endl; ReleaseMutex(cout_mutex); return 0L; } int main() { int a[10]; cout_mutex = CreateMutex(NULL, FALSE, NULL); for (int i = 0; i < 10; i++) { a[i] = i; HANDLE hThread = CreateThread(NULL, 0, MyThread, a + i, 0, NULL); } system("PAUSE"); return 0; }

    运行结果:

    可以看出输出正常了。

    I have 0 dolors! I have 1 dolors! I have 7 dolors! I have 5 dolors! I have 4 dolors! I have 6 dolors! I have 3 dolors! I have 9 dolors! I have 2 dolors!  

    4.指定线程运行核心:SetThreadAffinityMask()

    函数声明 DWORD_PTR SetThreadAffinityMask(HANDLE hThread, DWORD_PTR dwThreadAffinityMask); 使用方法: 第一个参数是线程的句柄(HANDLE),第二个参数用来指定CPU核心

    比如,你要指定进程到第0个CPU上,则mask=0×01 第1个CPU:mask=0×02 第2个CPU:mask=0×04 (注意不是0×03) 第3个CPU:mask=0×08

    3.代码实例:

    // 绑定到第三个核心 HANDLE hThread = CreateThread(NULL, 0, MyThread, a + i, 0, NULL); SetThreadAffinityMask(hThread, 0x08);
    Processed: 0.012, SQL: 9