标签:cpu put pac objects 为什么 进程创建 结束 单线程 iostream
什么是多线程,这在相关计算机原理的书籍里都有介绍,通常所说的多线程是指进程内的多线程,由进程创建一个私有线程表,自行管理自己的线程,这样好处是线程阻塞了,只会挂起进程,而不会影响到整个操作系统的运行。每个线程都有自己的栈,每创建一个线程就会分配一定的资源给线程,这就是为什么说要谨慎使用线程,否则会造成不必要的资源浪费,如果在Windows上,默认线程栈只有1M,不小心还会造成堆栈溢出。
C#、Java的多线程,最终映射到操作系统的本地线程实现。
我们可以通过代码演示一下,单线程和多线程在内存使用上的区别:
#include <iostream>
#include <time.h>
#include <math.h>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
void printSomething(int index) {
int a = index;
//去掉以下注释,以多线程的方式会报栈溢出
//char str[1024*996];
printf("%xd->%d\n", &a, a);
std::this_thread::sleep_for(1s);
}
int main()
{
std::cout << "non-thread\n";
for (int i = 0; i < 5; i++) {
//单线程输出相同的变量地址
printSomething(i);
}
std::cout << "thread\n";
std::thread t1[5];
for (int i = 0; i < 5; i++) {
//多线程输出不同的变量地址
t1[i]=std::thread(printSomething, i);
}
int x;
scanf_s("%d", &x);
}
输出结果:
non-thread
c1aff754d->0
c1aff754d->1
c1aff754d->2
c1aff754d->3
c1aff754d->4
thread
c1bff3a4d->0
c21ff504d->4
c1eff524d->1
c1fff8f4d->2
c20ff3e4d->3
所以对于线程,是不能烂用的,比如一个Socket服务器,通常会用单独线程去处理客户端的连接,如果每个连接都会开一个新的线程,势必对服务器的性能造成影响,因为要不停地分配栈空间,会浪费CPU时间和内存空间。特别是长连接的情况下,如果缓存中一直没有数据,那关联的线程就一直挂在那边,不做任何事,白浪费的资源。这种情况下,就会用到线程的另一种机制——线程池。可以让一个线程遍历所有的Socket,装有数据的扔给一个空闲的线程去处理就行了。
我们可以预先设置一组线程池,Windows上提供了一组Api用于实现线程池,原理就是将创建好的线程(绑定一个空函数)放在那等待,如果有任务来了,则发送一个解锁信号,领到任务的执行任务,没领到的继续等待。下边以Windows Api举个例子。
#include <iostream>
#include <time.h>
#include <math.h>
#include <thread>
#include <chrono>
#include <vector>
#include <queue>
#include <Windows.h>
using namespace std::chrono_literals;
const int len = 30;
HANDLE handle[len];//事件通知
int data[len];//测试数据
//任务
void printSomething(int index) {
int a = index;
auto tid = std::this_thread::get_id();
printf("%d:%xd->%d\n", tid, &a, a);
std::this_thread::sleep_for(200ms);
}
//任务回调
VOID CALLBACK workCall(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work) {
int* index = (int*)Context;
printSomething(*index);
SetEvent(handle[*index]);
}
int main()
{
std::cout << "non-thread\n";
for (int i = 0; i < len; i++) {
//单线程输出相同的变量地址
printSomething(i);
}
std::cout << "thread\n";
TP_CALLBACK_ENVIRON CallBackEnviron;
InitializeThreadpoolEnvironment(&CallBackEnviron);
auto pool = CreateThreadpool(NULL);
SetThreadpoolThreadMinimum(pool, 2);
SetThreadpoolThreadMaximum(pool, 2);
for (int i = 0; i < len; i++) {
data[i] = i;
handle[i] = CreateEvent(NULL, false, false, NULL);
auto work = CreateThreadpoolWork(workCall, &data[i], &CallBackEnviron);
//多线程输出不同的变量地址
SubmitThreadpoolWork(work);
}
//等待所有线程结束
WaitForMultipleObjects(5, handle, true, INFINITE);
CloseThreadpool(pool);
char x=getchar();
}
输出结果:
non-thread
57320:bf56fa84d->0
57320:bf56fa84d->1
57320:bf56fa84d->2
57320:bf56fa84d->3
57320:bf56fa84d->4
57320:bf56fa84d->5
57320:bf56fa84d->6
57320:bf56fa84d->7
57320:bf56fa84d->8
57320:bf56fa84d->9
57320:bf56fa84d->10
57320:bf56fa84d->11
57320:bf56fa84d->12
57320:bf56fa84d->13
57320:bf56fa84d->14
57320:bf56fa84d->15
57320:bf56fa84d->16
57320:bf56fa84d->17
57320:bf56fa84d->18
57320:bf56fa84d->19
57320:bf56fa84d->20
57320:bf56fa84d->21
57320:bf56fa84d->22
57320:bf56fa84d->23
57320:bf56fa84d->24
57320:bf56fa84d->25
57320:bf56fa84d->26
57320:bf56fa84d->27
57320:bf56fa84d->28
57320:bf56fa84d->29
thread
51292:bfcff574d->0
22580:bfdff834d->1
29532:bfeff3d4d->2
81420:bffff184d->3
80700:c00ff684d->4
51292:bfcff574d->5
22580:bfdff834d->6
29532:bfeff3d4d->7
81420:bffff184d->8
77684:c01ff3d4d->9
80700:c00ff684d->10
51292:bfcff574d->11
22580:bfdff834d->12
29532:bfeff3d4d->13
81420:bffff184d->14
54804:bf8ff644d->15
77684:c01ff3d4d->16
80700:c00ff684d->17
51292:bfcff574d->18
22580:bfdff834d->19
29532:bfeff3d4d->20
81420:bffff184d->21
56548:bfbff154d->22
54804:bf8ff644d->23
77684:c01ff3d4d->24
80700:c00ff684d->25
57176:c02ff264d->26
51292:bfcff574d->27
22580:bfdff834d->28
29532:bfeff3d4d->29
从输出结果中的线程id,可以看出线程被重复使用了,栈空间的指针也是相同的。
附C#示例:
using System;
using System.Threading;
public class Example
{
public static void Main()
{
// Queue the task.
ThreadPool.QueueUserWorkItem(ThreadProc);
Console.WriteLine("Main thread does some work, then sleeps.");
Thread.Sleep(1000);
Console.WriteLine("Main thread exits.");
}
// This thread procedure performs the task.
static void ThreadProc(Object stateInfo)
{
// No state object was passed to QueueUserWorkItem, so stateInfo is null.
Console.WriteLine("Hello from the thread pool.");
}
}
// The example displays output like the following:
// Main thread does some work, then sleeps.
// Hello from the thread pool.
// Main thread exits.
标签:cpu put pac objects 为什么 进程创建 结束 单线程 iostream
原文地址:https://www.cnblogs.com/icoolno1/p/12814142.html