标签:single 寄存器 c++ tco rda 程序 win return block
线程的组成:
栈区和栈区指针
程序计数器:PC
寄存器集合
线程的状态:
新建状态(New):刚被创建
准备状态(Runnable):加载所需的所有资源,等待CPU
运行状态(Running):被CPU执行
挂起状态(Blocked):阻塞,等待唤醒
1. 进程是资源分配的最小单元,线程是程序执行的最小单元。一个进程可以由一个或多个进程组成。
2. 从内存上:进程创建时会被分配地址空间,并且包含以下几种内存空间:堆区、栈区、代码区、全局变量区。
线程创建时会分配线程的私有栈,包括:维护参数和局部变量线程栈区,程序计数器(维护线程挂起再运行),寄存器集合等。
线程共享进程中除了线程上下文外的所有内存空间,包括(文件、系统资源等)
3. 从效率上:进程包含线程,并且拥有更多的数据结构需要维护。所以切换或者创建,进程的效率要慢于线程。
4. 安全性上:进程间有独立的地址空间,安全性较好;线程间虽然有私有的栈区,当理论上只要知道栈帧地址即可修改其他线程的变量。
1. __beginthreadex ( process.h中)
接口介绍:
unsigned long _beginthread( void(_cdecl *start_address)(void *), //声明为void (*start_address)(void *)形式 unsigned stack_size, //是线程堆栈大小,一般默认为0 void *arglist //向线程传递的参数,一般为结构体 ); unsigned long _beginthreadex( //推荐使用 void *security, //安全属性,NULL表示默认安全性 unsigned stack_size, //是线程堆栈大小,一般默认为0 unsigned(_stdcall *start_address)(void *), //声明为unsigned(*start_address)(void *)形式 void *argilist, //向线程传递的参数,一般为结构体 unsigned initflag, //新线程的初始状态,0表示立即执行,CREATE_SUSPEND表示创建后挂起(可用ResumeThread唤醒)。 unsigned *thrdaddr //该变量存放线程标识符,它是CreateThread函数中的线程ID。 ); //创建成功条件下的将线程句柄转化为unsigned long型返回,创建失败条件下返回0
使用示例:
#include<iostream> #include "windows.h" #include "process.h" using namespace std; unsigned __stdcall add100(void*) { long long sum = 0; for (int i = 0; i < 1000000; i++) { sum += i; } cout << sum << endl; return 1; } int main() { // 开启线程 unsigned int threadId; HANDLE hd1 = (HANDLE)_beginthreadex(NULL, 0, add100, NULL, NORMAL_PRIORITY_CLASS, &threadId); // 阻塞,等待线程函数结束 WaitForSingleObject(hd1, INFINITE); // 获取线程函数的返回值,线程函数如果没有执行return,则返回默认值 DWORD dwExitCode; GetExitCodeThread(hd1, &dwExitCode); }
__beginthreadex内部实现是调用CreareThread,但一般不推荐直接使用CreateThread,因为前者做了许多安全保护的工作。
具体原有参考:https://www.cnblogs.com/ay-a/p/9135652.html
中介三种创建线程的方式:
1) Create/EndThread是Win32方法开始/结束一个线程
2) _beginthreadx/_endthreadex是C RunTime方式开始/结束一个线程
3) AfxBeginThread是在MFC中开始/结束一个线程
https://www.cnblogs.com/lujin49/p/4557655.html
Note:
1. 直接在CreateThread API创建的线程中使用sprintf,malloc,strcat等涉及CRT存储堆操作的CRT库函数是很危险的,容易造成线程的意外中止。 在使用_beginthread和_beginthreadex创建的线程中可以安全的使用CRT函数。但是必须在线程结束的时候相应的调用_endthread或_endthreadex
2. _beginthread成对调用的_endthread函数内部隐式的调用CloseHandle关闭了线程句柄,而与_beginthreadex成对使用的_endthreadex则没有关闭线程的句柄,需要显示的调用CloseHandle关闭线程句柄,不要使用_beginthread,使用._beginthreadex代替之
3. 尽量不要在一个MFC程序中使用_beginthreadex()或CreateThread()。
4. 没有使用到MFC的线程尽量用_beginthreadex启动
使用方式:所有可执行的对象都可以放入thread中,包括,全局函数、类的成员函数、lambda表达式等。
#include<iostream> #include "thread" using namespace std; int add100(int cnt) { long long sum = 0; for (int i = 0; i < cnt; i++) { sum += i; } cout << sum << endl; return 1; } class A{ public: A() {} void test(int t) { this_thread::sleep_for(chrono::seconds(t)); cout << "sleep seconds: " << t << endl; } }; int main() { // 1. 普通函数放入线程执行 thread t1(add100, 100000); // 2. lambda表达式方式线程执行 thread t2([] { this_thread::sleep_for(chrono::seconds(2)); cout << "sleep 2 seconds. " << endl; }); // 3. 类的成员变量放入线程中执行 A a; thread t3(&A::test, a, 3); t1.join(); t2.join(); t3.join(); }
join:
等待子线程结束,阻塞。
detach:
将主线程与子线程分离,即不需要等待子线程结束,主线程也可以退出并不会报错。
yield:
交出当前线程的时间片,让当前线程放弃执行,让操作系统优先调用其他线程执行。
比如某个线程要等待某个变量,如果用死循环不断判断变量会耗费CPU性能,可以在等待时调用yield,交出时间片。
while(!isDone()); // Bad while(!isDone()) yield(); // Good
Note:
1. 线程thread对象无法被复制或拷贝,只能被move或swap
2. detach后不能调用join,同样join之后不能调用detach
其他关于C++11多线程的用法查考future。
标签:single 寄存器 c++ tco rda 程序 win return block
原文地址:https://www.cnblogs.com/dylan-liang/p/14751094.html