C++拾遗--多线程:多线程的引入
来源:互联网 发布:网络专供电器 编辑:程序博客网 时间:2024/05/16 01:31
转自:http://www.2cto.com/kf/201503/379541.html
C++拾遗--多线程:多线程的引入
前言
多线程是编程中的一个重要内容。多核时代使多线程成为一种可能,显然,一件事情多个人干,效率一定会提升。下面来看下C语言中是如何使用多线程的。
正文
1.CreateThread
先来看一个实例
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <windows.h>
DWORD WINAPI run(
void
*p)
{
char
*mess = (
char
*)p;
printf(线程%d,弹窗
, GetCurrentThreadId());
char
threadId[
20
];
sprintf(threadId, 线程%d, GetCurrentThreadId());
MessageBoxA(
0
, mess, threadId,
0
);
return
0
;
}
int
main(
void
)
{
printf(******C语言多线程演示***by David***
);
char
*mess[] = {
123
,
456
,
789
};
HANDLE handles[
3
];
for
(
int
i =
0
; i < sizeof(mess) / sizeof(*mess); i++)
{
handles[i] = CreateThread(NULL,
0
, run, mess[i],
0
, NULL);
}
WaitForMultipleObjects(
3
, handles,
1
, INFINITE);
return
0
;
}</process.h></stdlib.h></stdio.h>
异步弹出了三个窗口,并打印了各自的线程号。若是有没看懂的地方,下面有详细解释:
1.handle是句柄,在windows中用句柄来标识对象。本质很简单 typedef void * HANDLE;
2.CreateThread()用来创建线程。原型
HANDLE WINAPI CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, //内核对象的安全属性
SIZE_T dwStackSize, //线程栈大小
LPTHREAD_START_ROUTINE lpStartAddress, //线程函数地址
LPVOID lpParameter, //传给线程函数的参数
DWORD dwCreationFlags, //控制位
LPDWORD lpThreadId //获取线程id
);
参数解释:
第一个参数是线程内核对象的安全属性,一般传入NULL表示使用默认设置。
第二个参数是线程栈空间的大小。传入0表示使用默认大小(1MB)。
第三个参数是新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。
第四个参数是传给线程函数的参数。typedef void * LPVOID
第五个参数是用来控制线程的创建,0表示创建后立即执行。
第六个参数是传出参数,用来获得线程的id。显然,传入NULL,表示调用者并不想知道线程的id。
返回值:线程句柄
3.线程函数的声明。#define WINAPI __stdcall (vs2013)typedef unsigned long DWORD。其中,__stdcall是指C/CPP中函数的调用方式。主要有两点:1.实参从右向左入栈。2.调用者负责清空参数栈。
4.线程等待函数
DWORD WINAPI WaitForMultipleObjects(
DWORD nCount, //内核对象的个数
CONST HANDLE *lpHandles, //句柄数组的地址
BOOL bWaitAll, //是否等待所有
DWORD dwMilliseconds //等待的最大时间,单位毫秒,INFINITE表示无限等待
);
函数功能:让线程进入等待转态,直到条件触发。内核对象在运行期间处于未触发的状态,直到执行结束。
5.线程函数类型是
typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter);
更简洁的是
typedef unsigned long (__stdcall *pfun)(void*);
2._beginthreadex
函数原型
uintptr_t __cdecl _beginthreadex(
void* _Security,
unsigned _StackSize,
_beginthreadex_proc_type _StartAddress,
void* _ArgList,
unsigned _InitFlag,
unsigned* _ThrdAddr
);
它的参数类型和CreateThread基本一致,只是线程函数类型稍有不同。线程函数类型是
typedef unsigned (__stdcall *_beginthreadex_proc_type)(void*);
3._beginthread
CreateThread的调用过于复杂,下面我们玩儿个简单的,我们用多个线程打印 Hello World
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <windows.h>
void
hello(
void
*p)
{
printf(线程%d, say Hello World
, GetCurrentThreadId());
}
int
main()
{
printf(******C语言多线程演示***by David***
);
HANDLE handles[
5
];
for
(
int
i =
0
; i <
5
; i++)
{
handles[i] = _beginthread(hello,
0
, NULL);
}
WaitForMultipleObjects(
5
, handles,
1
, INFINITE);
getchar();
return
0
;
}</windows.h></process.h></stdlib.h></stdio.h>
_beginthread的原型
uintptr_t _beginthread(
_beginthread_proc_type _StartAddress, //线程函数的地址
unsigned _StackSize, //线程栈的大小
void* _ArgList //线程函数的参数
);
函数功能:使用指定线程函数创建线程,并返回线程句柄。
几点解释:
1.typedef unsigned int * uintptr_t;
2.typedef void(__cdecl *_beginthread_proc_type)(void*); _beginthread_proc_type就是一函数指针类型,我们提供的线程函数应该如此设计:只有一个参数,类型为void*,且返回值类型是void。
CreateThread和_beginthread的使用说明:
从函数参数可以看出,CreateThread用于对所创建的线程进行精细控制。在很多参数处于默认设置下,建议使用参数简单的_beginthread。两者所需的线程函数类型不同。
总结
使用多线程,就要先写好线程函数,然后调用相关函数创建线程即可。由于_beginthread传参简单,一般情况下,使用_beginthread创建多线程。
- C++拾遗--多线程:C语言多线程的引入
- C++拾遗--多线程:多线程的引入
- C++拾遗--C++多线程引入
- C语言多线程的引入
- 多线程拾遗
- Java多线程-多线程的引入
- Java多线程-多线程的引入
- 多核、多线程的引入
- 引入多线程的代价
- Java多线程的引入
- 多线程_多线程程序的引入
- Java拾遗-------多线程
- Java多线程拾遗
- 进程、线程、多线程的引入
- C++拾遗--多线程:主线程与子线程的同步
- JavaSE 拾遗(7)——JavaSE 多线程
- Java多线程编程核心技术---拾遗增补
- java多线程编程核心技术7-拾遗增补
- 11.27
- 0005算法笔记——【分治法】快速排序
- 11.创建模型
- Linux开发环境搭建(三)
- javascript学习之三(闭包)
- C++拾遗--多线程:多线程的引入
- 理解HTTP协议
- 搜索引擎学习笔记 --- 结构与模块图
- 翻译spring-cloud的一篇文章
- 算法的优化
- UiAutomator笔记之UiScrollable API(六)
- 开博首贴:HelloBolg
- 11月英语--慢慢回温
- php数组常用方法详解