CreateThread函数创建一个进程的新的线程。创建线程必须指定新线程要执行的代码的起始地址。通常,起始地址是程序代码中定义的函数的名称(有关更多信息,请参阅ThreadProc)。此函数采用单个参数并返回DWORD值。一个进程可以让多个线程同时执行相同的功能。

以下是演示如何创建执行本地定义函数的新线程的简单示例MyThreadFunction

调用线程使用WaitForMultipleObjects函数持久化,直到所有工作线程终止。调用线程在等待时阻塞; 为了继续处理,调用线程将使用WaitForSingleObject并等待每个工作线程发信号通知其等待对象。请注意,如果要在终止之前关闭工作线程的句柄,则不会终止工作线程。但是,句柄将不可用于后续函数调用。

#include <windows.h>
#include <tchar.h>
#include <strsafe.h>#define MAX_THREADS 3
#define BUF_SIZE 255DWORD WINAPI MyThreadFunction( LPVOID lpParam );
void ErrorHandler(LPTSTR lpszFunction);// Sample custom data structure for threads to use.
// This is passed by void pointer so it can be any data type
// that can be passed using a single void pointer (LPVOID).
typedef struct MyData {int val1;int val2;
} MYDATA, *PMYDATA;int _tmain()
{PMYDATA pDataArray[MAX_THREADS];DWORD   dwThreadIdArray[MAX_THREADS];HANDLE  hThreadArray[MAX_THREADS]; // Create MAX_THREADS worker threads.for( int i=0; i<MAX_THREADS; i++ ){// Allocate memory for thread data.pDataArray[i] = (PMYDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(MYDATA));if( pDataArray[i] == NULL ){// If the array allocation fails, the system is out of memory// so there is no point in trying to print an error message.// Just terminate execution.ExitProcess(2);}// Generate unique data for each thread to work with.pDataArray[i]->val1 = i;pDataArray[i]->val2 = i+100;// Create the thread to begin execution on its own.hThreadArray[i] = CreateThread( NULL,                   // default security attributes0,                      // use default stack size  MyThreadFunction,       // thread function namepDataArray[i],          // argument to thread function 0,                      // use default creation flags &dwThreadIdArray[i]);   // returns the thread identifier // Check the return value for success.// If CreateThread fails, terminate execution. // This will automatically clean up threads and memory. if (hThreadArray[i] == NULL) {ErrorHandler(TEXT("CreateThread"));ExitProcess(3);}} // End of main thread creation loop.// Wait until all threads have terminated.WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);// Close all thread handles and free memory allocations.for(int i=0; i<MAX_THREADS; i++){CloseHandle(hThreadArray[i]);if(pDataArray[i] != NULL){HeapFree(GetProcessHeap(), 0, pDataArray[i]);pDataArray[i] = NULL;    // Ensure address is not reused.}}return 0;
}DWORD WINAPI MyThreadFunction( LPVOID lpParam )
{ HANDLE hStdout;PMYDATA pDataArray;TCHAR msgBuf[BUF_SIZE];size_t cchStringSize;DWORD dwChars;// Make sure there is a console to receive output results. hStdout = GetStdHandle(STD_OUTPUT_HANDLE);if( hStdout == INVALID_HANDLE_VALUE )return 1;// Cast the parameter to the correct data type.// The pointer is known to be valid because // it was checked for NULL before the thread was created.pDataArray = (PMYDATA)lpParam;// Print the parameter values using thread-safe functions.StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d\n"), pDataArray->val1, pDataArray->val2); StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);WriteConsole(hStdout, msgBuf, (DWORD)cchStringSize, &dwChars, NULL);return 0;
} void ErrorHandler(LPTSTR lpszFunction)
{ // Retrieve the system error message for the last-error code.LPVOID lpMsgBuf;LPVOID lpDisplayBuf;DWORD dw = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS,NULL,dw,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPTSTR) &lpMsgBuf,0, NULL );// Display the error message.lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 40) * sizeof(TCHAR)); StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR),TEXT("%s failed with error %d: %s"), lpszFunction, dw, lpMsgBuf); MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK); // Free error-handling buffer allocations.LocalFree(lpMsgBuf);LocalFree(lpDisplayBuf);
}

MyThreadFunction函数避免使用C运行时库(CRT),因为它的许多函数都不是线程安全的,特别是如果您不使用多线程CRT。如果要在ThreadProc函数中使用CRT ,请改用_beginthreadex函数。

如果创建线程在新线程之前退出,则传递局部变量的地址是有风险的,因为指针变为无效。相反,要么将指针传递给动态分配的内存,要么让创建线程等待新线程终止。数据也可以使用全局变量从创建线程传递到新线程。对于全局变量,通常需要通过多个线程同步访问。有关同步的详细信息,请参阅同步多个线程的执行。

创建线程可以使用CreateThread的参数来指定以下内容:

新线程句柄的安全属性。这些安全属性包括一个继承标志,用于确定子进程是否可以继承句柄。安全性属性还包括安全描述符,系统使用该描述符在授予访问权限之前对线程句柄的所有后续使用执行访问检查。
新线程的初始堆栈大小。线程的堆栈自动分配在进程的内存空间中; 系统根据需要增加堆栈,并在线程终止时释放它。有关更多信息,请参阅线程堆栈大小。
一个创建标志,使您可以创建处于挂起状态的线程。挂起时,线程不会运行,直到调用ResumeThread函数。
您还可以通过调用CreateRemoteThread函数来创建线程。调试器进程使用此函数来创建在正在调试的进程的地址空间中运行的线程。

相关话题

终止线程

使用线程——创建线程相关推荐

  1. [Linux]线程概念_线程控制(线程与进程的区别与联系 | 线程创建 | 线程等待 | 线程终止 | 线程分离 | LWP)

    文章目录 线程概念 进程和线程的关系 线程的优点 线程的缺点 线程控制 Linux线程和接口关系的认识 线程创建 线程ID及进程地址空间布局 线程等待 线程终止 线程终止状态 线程分离 LWP和pth ...

  2. java 继承thread_java线程-创建线程(继承 Thread 类)

    1.创建线程的方式 线程创建方式是:继承 Thread 类,重写 run 方法.如下:public class Task extends Thread{ @Override public void r ...

  3. 【Android NDK 开发】JNI 线程 ( JNI 线程创建 | 线程执行函数 | 非 JNI 方法获取 JNIEnv 与 Java 对象 | 线程获取 JNIEnv | 全局变量设置 )

    文章目录 I . JNI 线程创建 II . 线程执行函数 III . 线程方法获取 Java 对象 IV . 线程方法获取 JNIEnv V . JNI 线程 完整代码示例 I . JNI 线程创建 ...

  4. java多线程-线程创建-线程池-java内存模型

    文章目录 ==多线程基础== 进程 线程 浏览器的进程和线程(案例) 线程的异步和同步 多线程的优势 ==多线程的实现方式== 第一种:继承Thread类 第二种:实现Runnable接口 第三种:通 ...

  5. 线程 --- 创建线程的七种方法

    目录 方法1 :继承Thread类,重写run方法,调用 start 方法启动 方法2 :实现Runnable接口,重写run方法,调用 start 方法启动 方法3:匿名内部类 创建Thread 子 ...

  6. 黑马毕向东Java课程笔记(day11):多线程(第一部分)——进程与线程+线程创建+线程安全与同步代码块+同步锁/死锁

    多线程好文:添加链接描述 锁机制:synchronized.Lock.Condition.volatile(原子性可见性)--参考添加链接描述 1.进程与线程概述   首先,对于CPU执行每一个程序, ...

  7. 【C++ 语言】线程 ( 线程创建方法 | 线程标识符 | 线程属性 | 线程属性初始化 | 线程属性销毁 | 分离线程 | 线程调度策略 | 线程优先级 | 线程等待 )

    文章目录 I 线程创建方法 II 线程执行函数 III 线程标识符 IV 线程属性 V 线程属性 1 ( 分离线程 | 非分离线程 ) VI 线程属性 2 ( 线程调度策略 ) VII 线程属性 3 ...

  8. java创建线程几种_java中创建线程有几种方式

    详细内容 线程的创建方式 1.继承Thread类实现多线程 2.覆写Runnable()接口实现多线程,而后同样覆写run().推荐此方式 3.使用Callable和Future创建线程 相关视频教程 ...

  9. Linux 线程优先级设置(内含C语言版线程创建、绑定CPU和优先级设置代码)

    参考链接: https://blog.csdn.net/wushuomin/article/details/80051295 //详细讲解pthread_create 函数 https://blog. ...

最新文章

  1. Matlab | Matlab从入门到放弃(7)——struct结构体
  2. Xen虚拟机迁移技术
  3. base64编码以及url safe base64是怎么工作的?
  4. windows下编译firefox
  5. leetcode435. 无重叠区间(贪心算法)
  6. 这次,甘肃的老百姓办理就医再也不用等了
  7. db2中TRANSLATE函数可以实现简单的正则(不属于真正的正则表达式)
  8. 文本格式化标签(HTML)
  9. CCF201609-2 火车购票(100分)
  10. oracle union orderby,Oracle UNION和ORDER BY的奇怪问题
  11. upupoo怎么设置本地html文件,关于Upupoo自定义元素教程
  12. [转载]软件测试学习资料
  13. 应用Matlab小波变换工具箱进行图像压缩
  14. 手把手教你如何做一套utm广告投放
  15. vue项目中Echarts两个图表之间连接两条线
  16. python将字典按行或按列写入csv文件
  17. 基于java的驾校驾照在线考试系统-计算机毕业设计
  18. 没有开发经验的程序员,怎么快速学习进入工作?
  19. cstring与string区别联系
  20. Zabbix 3.0 版本企业微信群机器人报警

热门文章

  1. java 反射 代码_java反射机制学习代码
  2. 如何将文件拷贝服务器上,如何将文件复制到云服务器上
  3. 网站前端组织冒泡事件
  4. mysql触发器生成流水_利用mysql触发器生成流水号
  5. QT5生成.exe文件时,出现缺少QT5core.dll文件解决方法
  6. Java提高篇 —— Java三大特性之多态
  7. MSYS2 + MinGW-w64 + Git + gVim 环境配置
  8. 历史上最有影响力的10款开源项目
  9. 关于 std::set/std::map 的几个为什么
  10. 四大电商对垒价格战:家电高库存或是推手