Linux 下C语言简单实现线程池

嵌入式技术笔记(十八):线程池 1. 多线程存在的问题 1、进程所支持的线程数量问题(受限) 2、线程的创建和销毁的开销问题 2. 线程池的概念 3. 创建线程池 任务: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <unistd.h> struct job { void *((*func)(void *arg)); void 阅读详情

C语言简单实现线程池

0 前言

网上关于线程池的例子还是不少,简单明了的倒是比较少,看了网上的资料,打算借鉴网上的一些例子,自己实现以下。

线程的概念就不多说,首先说一下多线程的好处:多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。

那么为什么又需要线程池呢?

我们知道应用程序创建一个对象,然后销毁对象是很耗费资源的。创建线程,销毁线程,也是如此。因此,我们就预先生成一些线程,等到我们使用的时候在进行调度,于是,一些"池化资源"技术就这样的产生了。

 

1 线程池优点

下面使用网上资源验证线程池如何提高服务器性能的。

我所提到服务器程序是指能够接受客户请求并能处理请求的程序,而不只是指那些接受网络客户请求的网络服务器程序。

多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。但如果对多线程应用不当,会增加对单个任务的处理时间。可以举一个简单的例子:

假设在一台服务器完成一项任务的时间为T

     T1 创建线程的时间

      T2 在线程中执行任务的时间,包括线程间同步所需时间

      T3 线程销毁的时间              

显然T = T1+T2+T3。注意这是一个极度简化的假设。

可以看出T1,T3是多线程本身的带来的开销,我们渴望减少T1,T3所用的时间,从而减少T的时间。但一些线程的使用者并没有注意到这一点,所以在程序中频繁的创建或销毁线程,这导致T1和T3在T中占有相当比例。显然这是突出了线程的弱点(T1,T3),而不是优点(并发性)。

线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。

线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。在看一个例子:

假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。我们比较利用线程池技术和不利于线程池技术的服务器处理这些请求时所产生的线程总数。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目或者上限(以下简称线程池尺寸),而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池尺寸是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。

这些都是假设,不能充分说明问题,下面我将讨论线程池的简单实现并对该程序进行对比测试,以说明线程技术优点及应用领域。

 

2 线程池的简单实现

一般一个简单线程池至少包含下列组成部分。

  1. 线程池管理器(ThreadPoolManager):用于创建并管理线程池
  2. 工作线程(WorkThread): 线程池中线程
  3. 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。
  4. 任务队列:用于存放没有处理的任务。提供一种缓冲机制。

 

下面是代码:

全局文件:

/********************************** 
 * @author     wallwind@yeah.net
 * @date        2012/06/13
 * Last update: 2012/06/13
 * License:     LGPL
 * 
 **********************************/
 
 #ifndef _GLOBAL_H_
 #define _GLOBAL_H_
 
 #include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>             /* */
#include <stdarg.h>
#include <stddef.h>             /* offsetof() */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <dirent.h>
#include <glob.h>
#include <sys/vfs.h>            /* statfs() */

#include <sys/uio.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sched.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>        /* TCP_NODELAY, TCP_CORK */
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/un.h>

#include <time.h>               /* tzset() */
#include <malloc.h>             /* memalign() */
#include <limits.h>             /* IOV_MAX */
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <crypt.h>
#include <sys/utsname.h>        /* uname() */
#include <semaphore.h>

#include <sys/epoll.h>
#include <poll.h>
#include <sys/syscall.h>
#include <pthread.h>
 #endif


thread.c文件

/********************************** 
 * @author      wallwind@yeah.net
 * @date        2012/06/13
 * Last update: 2012/06/13
 * License:     LGPL
 * 
 **********************************/
 
 
 
 #ifndef _THPOOL_
 #define _THPOOL_
 
 #include "global.h"
 /**
	定义一个任务节点
 **/
 typedef void* (*FUNC)(void* arg);
 
 
 typedef struct _thpool_job_t{
//	void* (*function)(void* arg);    //函数指针
	FUNC 			 function;
	void*                   arg;     //函数参数。
	struct _thpool_job_t* prev;     // 指向上一个节点
	struct _thpool_job_t* next;	    //指向下一个节点
 } thpool_job_t;
 
 /**
	定义一个工作队列
 **/
 
typedef struct _thpool_job_queue{
	thpool_job_t*    head;            //队列头指针 
	thpool_job_t*    tail;			   // 队列末尾指针
	int              jobN;					  //任务数
	sem_t*           queueSem;			  //x信号量
}thpool_jobqueue; 
 
 /**
	线程池
 **/
 
 typedef struct _thpool_t{
	pthread_t*      threads;    ////线程指针数
	int 		    threadsN;    //// 线程数
	thpool_jobqueue* jobqueue;   // 指向队列指针
 }thpool_t;
 
 typedef struct thread_data{                            
	pthread_mutex_t *mutex_p;
	thpool_t        *tp_p;
}thread_data;

 //初始化线程池内部的线程数
thpool_t*  thpool_init(int threadN);

void thpool_thread_do(thpool_t* tp_p);

int thpool_add_work(thpool_t* tp_p, void *(*function_p)(void*), void* arg_p);

void thpool_destroy(thpool_t* tp_p);



int thpool_jobqueue_init(thpool_t* tp_p);



void thpool_jobqueue_add(thpool_t* tp_p, thpool_job_t* newjob_p);

int thpool_jobqueue_removelast(thpool_t* tp_p);

thpool_job_t* thpool_jobqueue_peek(thpool_t* tp_p);

void thpool_jobqueue_empty(thpool_t* tp_p);

 #endif

 

thread.c

/********************************** 
 * @author     wallwind@yeah.net
 * @date        2012/06/13
 * Last update: 2012/06/13
 * License:     LGPL
 * 
 **********************************/
 #include "global.h"
 #include "Thread.h"
 #include <errno.h>
 
 static int thpool_keepalive = 1;
 
 /* 创建互斥量,并初始化 */
  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /* used to serialize queue access */
 
thpool_t*  thpool_init(int threadN)
{
	thpool_t* thpool;
	if(!threadN || threadN < 1)
		threadN = 1;
	///分配线程池内存
	thpool = (thpool_t*) malloc(sizeof(thpool_t));
	if(thpool ==NULL)
	{
		printf("malloc thpool_t error");
		return NULL;
	}
	//分配线程数
	thpool->threadsN = threadN;
	thpool->threads =(pthread_t*) malloc(threadN*sizeof(pthread_t));
	if(thpool->threads == NULL)
	{
		printf("malloc thpool->threads error");
		return NULL;
	}
	if(thpool_jobqueue_init(thpool))
		return -1;

	thpool->jobqueue->queueSem =(sem_t*)malloc(sizeof(sem_t));
	sem_init(thpool->jobqueue->queueSem,0,1);
	int t;
	for(t = 0;t< threadN ;t++)
	{
		pthread_create(&(thpool->threads[t]),NULL,(void *)thpool_thread_do,(void*)thpool);
	}
	
	return thpool;
}

void thpool_destroy(thpool_t* tp_p)
{
	int i ;
	thpool_keepalive = 0;
	
	for(i = 0;i < (tp_p->threadsN); i++)
	{
		if(sem_post(tp_p->jobqueue->queueSem))
		{
			fprintf(stderr, "thpool_destroy(): Could not bypass sem_wait()\n");
		}

	}
	if(sem_post(tp_p->jobqueue->queueSem)!=0)
	{
		fprintf(stderr, "thpool_destroy(): Could not destroy semaphore\n");
	}
	for(i = 0;i < (tp_p->threadsN); i++)
	{
		pthread_join(tp_p->threads[i],NULL);
	}
	thpool_jobqueue_empty(tp_p);
	
	free(tp_p->threads);
	free(tp_p->jobqueue->queueSem);
	free(tp_p->jobqueue);
	free (tp_p);
	
}
////对双向队列初始化
/* Initialise queue */
int thpool_jobqueue_init(thpool_t* tp_p){
	tp_p->jobqueue=(thpool_jobqueue*)malloc(sizeof(thpool_jobqueue));      /* MALLOC job queue */
	if (tp_p->jobqueue==NULL) return -1;
	tp_p->jobqueue->tail=NULL;
	tp_p->jobqueue->head=NULL;
	tp_p->jobqueue->jobN=0;
	return 0;
}

////
void thpool_thread_do(thpool_t* tp_p)
{
	while(thpool_keepalive ==1)
	{
		if(sem_wait(tp_p->jobqueue->queueSem)) ///线程阻塞,等待通知 直到消息队列有数据
		{
			perror("thpool_thread_do(): Waiting for semaphore");
			exit(1);
		}
		if(thpool_keepalive)
		{
			//(void*)(*function)(void *arg);
			FUNC function;
			void* arg_buff;
			thpool_job_t*  job_p;
			
			pthread_mutex_lock(&mutex);
			 job_p = thpool_jobqueue_peek(tp_p);
			function = job_p->function;
			arg_buff = job_p->arg;
			if(thpool_jobqueue_removelast(tp_p))
				return ;
			pthread_mutex_unlock(&mutex);
			function(arg_buff);   //运行 你的方法。
			free(job_p);         ////释放掉。
		}
		else
		{
			return ;
		}
			
	}
	return ;
}

//得到第一个队列的一个节点
thpool_job_t* thpool_jobqueue_peek(thpool_t* tp_p)
{
	return tp_p->jobqueue->tail;
}
/////删除队列的最后一个节点
int thpool_jobqueue_removelast(thpool_t* tp_p)
{
	if(tp_p ==NULL)
		return -1;
	thpool_job_t* theLastJob;
	theLastJob = tp_p->jobqueue->tail;
	switch(tp_p->jobqueue->jobN)
	{
		case 0:
			return -1;
		case 1:
			tp_p->jobqueue->head =NULL;
			tp_p->jobqueue->tail =NULL;
			break;
		default:
			theLastJob->prev->next = NULL;
			tp_p->jobqueue->tail = theLastJob->prev;
				
	}
	(tp_p->jobqueue->jobN)--;
	int reval;
	sem_getvalue(tp_p->jobqueue->queueSem,&reval);
	return 0;	
}

void thpool_jobqueue_add(thpool_t* tp_p, thpool_job_t* newjob_p)
{
	newjob_p->next = NULL;
	newjob_p->prev = NULL;
	thpool_job_t* oldFirstJob;
	oldFirstJob = tp_p->jobqueue->head;
	
	switch(tp_p->jobqueue->jobN)
	{
		case 0:
			tp_p->jobqueue->head = newjob_p;
			tp_p->jobqueue->tail = newjob_p;
			break;
		default:
			oldFirstJob->prev = newjob_p;
			newjob_p->next = oldFirstJob;
			tp_p->jobqueue->head = newjob_p;
	
	}
	(tp_p->jobqueue->jobN)++;
	sem_post(tp_p->jobqueue->queueSem);
	
	int reval;
	sem_getvalue(tp_p->jobqueue->queueSem,&reval);
	return;
}

/////将消息加入线程池
int thpool_add_work(thpool_t* tp_p, void* (*function_p)(void*), void* arg_p)
{
	thpool_job_t* newjob;
	newjob = (thpool_job_t*) malloc(sizeof(thpool_job_t));
	
	if(newjob ==NULL)
	{
		fprintf(stderr, "thpool_add_work(): Could not allocate memory for new job\n");
		exit(1);
	}
	newjob ->function = function_p;
	newjob ->arg      = arg_p;
	pthread_mutex_lock(&mutex);
	thpool_jobqueue_add(tp_p,newjob);
	pthread_mutex_unlock(&mutex);     
	return 0;
}

///清空队列
void thpool_jobqueue_empty(thpool_t* tp_p)
{
	thpool_job_t* curjob;
	curjob = tp_p->jobqueue->tail;
	
	while(tp_p->jobqueue->jobN)
	{
		tp_p->jobqueue->tail = curjob->prev;
		free (curjob);
		curjob = tp_p->jobqueue->tail;
		(tp_p->jobqueue->jobN)--;
	}
	tp_p->jobqueue->head = NULL;
	tp_p->jobqueue->tail = NULL;
}



下面是mian函数文件

/********************************** 
 * @author      wallwind@yeah.net
 * @date        2012/06/13
 * Last update: 2012/06/13
 * License:     LGPL
 * 
 **********************************/

#include "global.h"
#include "Thread.h"

	void* task1()
	{
		printf("# Thread working: %u\n", (int)pthread_self());
		printf("  Task 1 running..\n");
	}


    /* Some arbitrary task 2 */
	void* task2(int a)
	{
		printf("# Thread working: %u\n", (int)pthread_self());
		printf("  Task 2 running..\n");
		printf("%d\n", a);
	}
int main()
{
	printf("~~~~~~~~~~~");
	thpool_t* thpool;
	int i;
	thpool = thpool_init(5);
	puts("Adding 20 tasks to threadpool");
	int a=54;
	for (i=0; i<20; i++){
		thpool_add_work(thpool, (void*)task1, NULL);
		thpool_add_work(thpool, (void*)task2, (void*)a);
	};


    puts("Will kill threadpool");
	thpool_destroy(thpool);
	
}


在linux下写程序少不了makefile文件。于是我自己写了一个比较通用的makefile文件。仅供大家参考

makefile 代码

SRCS=$(wildcard *.c)

OBJS=$(SRCS:.c=.o)

CC=gcc

INCLUDES=-I/

LIBS=-L/ -lpthread

CCFLAGS = -g -Wall -O0

cThreadPool : $(OBJS)

        $(CC) $^ -o $@ $(INCLUDES) $(LIBS)

%.o : %.cpp

        $(CC) -c $<$(CCFLAGS)


clean:

        rm *.o

        .PHONY:clean

运行效果如下图

./test
Created thread 0 in pool 
Created thread 1 in pool 
Created thread 2 in pool 
Created thread 3 in pool 
Adding 20 tasks to threadpool
# Thread working: 3086773136
  Task 1 running..
# Thread working: 3076283280
  Task 2 running..
54
# Thread working: 3086773136
  Task 1 running..
# Thread working: 3086773136
  Task 2 running..
54
# Thread working: 3076283280
  Task 1 running..
# Thread working: 3086773136
  Task 2 running..
54
# Thread working: 3076283280
  Task 1 running..
# Thread working: 3086773136
  Task 2 running..
54
# Thread working: 3076283280
  Task 1 running..
# Thread working: 3086773136
  Task 2 running..
54
# Thread working: 3076283280
  Task 1 running..
# Thread working: 3086773136
  Task 2 running..
54
# Thread working: 3076283280
  Task 1 running..
# Thread working: 3086773136
  Task 2 running..
54
# Thread working: 3076283280
  Task 1 running..
# Thread working: 3086773136
  Task 2 running..
54
# Thread working: 3076283280
  Task 1 running..
# Thread working: 3086773136
  Task 2 running..
54
# Thread working: 3076283280
  Task 1 running..
# Thread working: 3086773136
  Task 2 running..
54
Will kill threadpool


线程池也是参考了别人的。

 

更多文章欢迎访问:http://blog.youkuaiyun.com/wallwind 



 

实现Linux下的C语言简单线程池编程 线程池的基本原理是在程序启动时创建一定数量的线程,并将它们保存在一个线程池中。当需要执行某个任务时,可以从线程池中获取一个空闲的线程,并将任务分配给该线程执行。通过使用线程池,我们可以更加高效地管理和复用线程,提高程序的性能和效率。线程池是一种常用的并发编程技术,它可以在多线程环境下管理和复用线程,提高程序的性能和效率。在本篇文章中,我们将使用C语言实现一个简单的线程池,并介绍其基本原理和代码实现。函数用于向线程池添加任务,它会将任务添加到任务队列中,并通知一个等待中的线程去执行任务。 阅读详情

相关推荐

Docker新手必看:解决‘Unable to find image’错误的完整指南

本文针对Docker新手常见的‘Unable to find image’错误,提供了完整的排查与解决指南。文章深入剖析了权限不足、网络连接失败、Docker服务未运行等核心原因,并给出了将用户加入docker组、配置镜像加速器等实用解决方案,帮助读者彻底理解并解决镜像拉取问题。

weixin_29230901的博客 241

进程和线程在Linux环境中c语言编程

对现场线程和进程的总结,以在编程中使用的函数

weixin_43819521的博客 878

【Tessent Shell Users Manual】【Ch3】Design Introspection and Editing(未完待续)

Tessent Shell 提供了一系列用于检查(examining/introspecting)和编辑design的命令。

Tranquil_ovo的博客 1730

JAVA------多线程之探究同步

问题提出 今假设今天晚上北京到上海的高铁只剩下1张二等座,购票流程为查询余票,付钱,出票三个步骤。此时张三和李四分别在不同的窗口购票,若此时没有同步机制,则可能出现张三在出票前,李四查询任然有一张余票,可付款,出票,则此时会出现一张票同时卖给两个人。这种情况当然是不允许的,不然春运回家时会发现你的座位上坐着一个抠脚大汉。。。。 解决方法 解决方法很简单,只要保证张三访问火车票在退出(出票)前,其他人(李四)不能够访问操作这张票就可以。 线程同步 由上述例子...

山海可平的博客 346

HALCON实战:用两个工业相机实现无缝大视野拼接(附完整代码与避坑指南)

本文详细介绍了使用HALCON软件实现双工业相机图像无缝拼接的完整解决方案,涵盖硬件配置、相机标定、坐标系转换和图像拼接等关键步骤。通过高精度标定和矩阵变换技术,可构建大视野检测系统,适用于液晶面板、PCB等工业检测场景,显著提升检测效率和精度。

weixin_29050513的博客 188

【TCGA-CRC】TCGA数据读取

本文介绍了如何从TCGA数据库中处理结肠癌(COAD)和直肠癌(READ)的RNA测序数据。首先,通过data.table::fread函数读取基因表达量文件,并检查基因ID和基因名称的一致性。接着,批量读取所有样本的TPM(Transcripts Per Million)数据,并将其合并为表达矩阵。随后,通过匹配样本ID和文件名,确保表达矩阵的列名与样本ID一致。最后,筛选出编码蛋白质的基因,并将处理后的数据保存为Rdata文件。整个过程涉及数据读取、合并、匹配和筛选,为后续的基因表达分析提供了基础。

小八四爱吃甜食的博客 662

嵌入式笔记20 链表(任务队列 线程池)

文章目录一、多线程存在的问题二、使用步骤1.引入库2.读入数据总结 一、多线程存在的问题 1、进程所支持的线程数量问题(受限) 2、线程的创建和销毁的开销问题 任务队列为空时,线程池里的线程阻塞等待 任务里的线程队列不为空,线程池里的线程处理任务 任务队列为满,不能添加新的任务 线程池里线程的数量 任务队列的大小 任务队列的锁 int thread_num / /已开启的线程数量 void *(*func)(void *arg);//任务行数、 struct job *next;//定义指针 str

qq_49181551的博客 496

地磁场仿真与导航方案设计

地磁场仿真与导航方案设计 地磁场作为地球的固有资源,为航空、航天、航海提供了天然的坐标,可应用于航天器、航空飞行器和舰船等载体的定位、定向及姿态控制。本文依据地磁场的球谐模型,利用Matlab工具,设计了计算任意地点地磁场的程序,对仿真结果与实际数据进行对比分析;并选定一组卫星的数据,结合卫星的运动轨道,描绘90分钟内卫星处地磁总强度/矢量随轨道变化曲线,据此设计一种卫星地磁导航方案。 一、地磁场计算原理 1.1.球谐模型与球谐系数 地磁学的基本问题之一就是用数学表达式将地磁要素的地面分布表示成地理坐标的函

PRQKKK的博客 7404

linux下c语言简单线程池实现

#include #include #include #include #include typedef struct thread_task_s thread_task_t;typedef struct thread_pool_s thread_pool_t;struct thread_task_s{ void *(*process)(void *arg); void *arg; thread_

差落的专栏 501

在 NVIDIA DGX Spark 上运行 vLLM + Open WebUI

DGX Spark 和 GX10 都是性能强大的机器,但只有将它们视为交互式工作站而非精简版服务器,才能真正发挥它们的优势。合理利用共享资源,规划并发工作负载,并谨慎控制内存限制。做到这些,vLLM 与 Open WebUI 的结合就能成为可靠​​的日常工具,而不是脆弱的实验品。DGX平台本身价格不菲,但这并非体验此类硬件的唯一途径。多家厂商提供基于相同核心架构、价格更为亲民的系统,这些系统通常配备容量较小的固态硬盘或配置更为简化,但基本性能并未改变。

iCloudEnd的博客 1749

《PCI Express体系结构导读1》-- PCI简介

请先阅读完一遍此书再来看文章哦,这样效率更高~

HoneyIC的博客 150

linux下C语言实现简单线程池

实现一个简单的线程池 我们知道同一进程中的多条线程将共享该进程中的全部系统资源,频繁的创建和结束线程会占用大量的系统资源,而线程池可以避免这种情况。 简单的来说,线程池就是多个线程的集合。这些线程在执行完当前任务后不会立即结束,而是执行下一个任务。若没有任务可执行,它们就会阻塞并等待下一个任务。线程池只在销毁时会结束所有线程。这样以来就避免了频繁创建和结束线程的情况,下面讲讲如何实现一个简单的线程池。 作者的线程池主要是由多个常驻线程和任务队列组成的。任务队列由链表来实现,里面的每个任务中都有相应的处理函数

A7SS5的博客 325

FC7300 Clock介绍

FC7300的时钟架构包括一个高级时钟图和内部时钟需求。它有5个CMU,使用SIRC监控FIRC/SOSC/FOSC,并使用FIRC监控SIRC。此外,CMU4还使用FOSC监Slow Clock。

舊梦的博客 327

linux下用c语言实现一个简单的线程池

首先大家思考一个问题:为什么需要内存池? 我们知道应用程序创建一个对象,然后销毁对象是很耗费资源的。创建线程,销毁线程,也是如此。因此,我们就预先生成一些线程,等到我们使用的时候在进行调度,于是,一些"池化资源"技术就这样的产生了。 1 线程池优点 下面使用网上资源验证线程池如何提高服务器性能的。 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单

hj605635529的博客 4169

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

linux下C语言简单实现线程池

0 前言 网上关于线程池的例子还是不少,简单明了的倒是比较少,看了网上的资料,打算借鉴网上的一些例子,自己实现以下。 线程的概念就不多说,首先说一下多线程的好处:多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。 那么为什么又需要线程池呢? 我们知道应用程序创建一个对象,然后销毁对象是很耗费资源的。创建线程,销毁线程,也是如此。

rayylee 949

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

c++ socket线程池_Linux 下C语言简单实现线程池

线程的概念就不多说,首先说一下多线程的好处:多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。那么为什么又需要线程池呢?我们知道应用程序创建一个对象,然后销毁对象是很耗费资源的。创建线程,销毁线程,也是如此。因此,我们就预先生成一些线程,等到我们使用的时候在进行调度,于是,一些"池化资源"技术就这样的产生了。1 线程池优点我所提到服务器...

weixin_39752800的博客 213

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

【收集】Linux线程池(C语言)及简单实现示例

【收集】Linux线程池(C语言)及简单实现示例 1.线程池基本原理   在传统服务器结构中, 常是 有一个总的 监听线程监听有没有新的用户连接服务器, 每当有一个新的 用户进入, 服务器就开启一个新的线程用户处理这 个用户的数据包。这个线程只服务于这个用户 , 当 用户与服务器端关闭连接以后, 服务器端销毁这个线程。然而频繁地开辟与销毁线程极大地占用了系统的资源。而且在大量用户的情况

GengLUT 1175

linux下c语言实现简单----线程池

这两天刚好看完linux&c这本书的进程线程部分,学长建议可以用c语言实现一个简单的线程池,也是对线程知识的一个回顾与应用。线程的优点有好多,它是”轻量级的进程”,所需资源少,多线程共享数据空间,线程之间切换速度更快,可以减少服务器的闲置时间等。那么我们要在往高层次讲它也有一些缺点,比如一个多线程的程序在创建和销毁线程的时候是比较费资源的,举一个例子,我们要是自己是一个普通饭店老板,当顾客来了我们再

杨博东的博客 2665

Linux线程池(C语言)及简单实现示例

线程池基本原理   在传统服务器结构中, 常是 有一个总的 监听线程监听有没有新的用户连接服务器, 每当有一个新的 用户进入, 服务器就开启一个新的线程用户处理这 个用户的数据包。这个线程只服务于这个用户 , 当 用户与服务器端关闭连接以后, 服务器端销毁这个线程。然而频繁地开辟与销毁线程极大地占用了系统的资源。而且在大量用户的情况下, 系统为了开辟和销毁线程将浪费大量的时间和资源。线程池提供了

ygl的记录博 647
上一篇: awk 用法小结
下一篇: 浅谈GCC预编译头技术
ctreewang
博客等级 码龄16年 1608粉丝 276原创
评论 10
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值