系统架构——多线程的应用

2021-02-01 10:16

阅读:488

标签:cpu   put   pac   objects   为什么   进程创建   结束   单线程   iostream   

什么是多线程,这在相关计算机原理的书籍里都有介绍,通常所说的多线程是指进程内的多线程,由进程创建一个私有线程表,自行管理自己的线程,这样好处是线程阻塞了,只会挂起进程,而不会影响到整个操作系统的运行。每个线程都有自己的栈,每创建一个线程就会分配一定的资源给线程,这就是为什么说要谨慎使用线程,否则会造成不必要的资源浪费,如果在Windows上,默认线程栈只有1M,不小心还会造成堆栈溢出。

C#、Java的多线程,最终映射到操作系统的本地线程实现。

我们可以通过代码演示一下,单线程和多线程在内存使用上的区别:

#include 
#include 
#include 
#include 
#include 
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
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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
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


评论


亲,登录后才可以留言!