user-0 提问: UDP+线程池处理问题！

回复:
user: user-1
content: 看看unix网络编程，上面有你需要的所有消息

user: user-0
content: 引用 29 楼 u014149003 的回复:在做FTP和email 客户端的时候用的也是线程池，线程池不是类似生产者-消费者么 只要锁的力度和区域设计好，一切都会变得很简单~ 嗯，是的，不过现在遇到的问题是要在线程池中进行数据处理，而数据处理用到了别人封装的一个静态库，现在看来这个静态库不是线程安全的，如果锁住了这个静态库提供的函数，那就跟顺序执行没什么两样了，得不到并发执行线程池也就没什么意义了。

user: user-2
content: 在做FTP和email 客户端的时候用的也是线程池，线程池不是类似生产者-消费者么 只要锁的力度和区域设计好，一切都会变得很简单~

user: user-0
content: 引用 16 楼 dooX8086 的回复:相关楼主还要注意  惊群现象   （pthread_cond_signal  惊群）  process 函数中的 iRet = Enc(gtSlot[iSessID].pHandle, &sBuf[0], tSndBuf.ucText);//   这个gtSolt 那里来的？ 看样子就个公共变量，还有 iSessID .... 等公共变量，如果外部没有保证这些变量 这个 函数不是线程安全的  对于 process 函数 process(...);       // 如果它是放在 这行mutex_unlock() 之前,那么这个 多线程的设计10分不好(比单线程还慢得多) pthread_mutex_unlock() <<=========  //  较好的设计它应该放在 mutex_unlock() 这后 高人，不知道能不能跟您继续学习讨论一下呢？

user: user-3
content: 这样吗 我怎么知道不得

user: user-4
content: 关注下,不错

user: user-5
content: 这个规划有点怪怪的

user: user-0
content: 引用 24 楼 qq_30773211 的回复:这样吗 我怎么知道不得 没明白，什么意思？

user: user-0
content: 引用 20 楼 cattpon 的回复:这个规划有点怪怪的 那里比较怪啊？

user: user-6
content: 学习

user: user-7

user: user-0
content: 引用 16 楼 dooX8086 的回复:相关楼主还要注意  惊群现象   （pthread_cond_signal  惊群）  process 函数中的 iRet = Enc(gtSlot[iSessID].pHandle, &sBuf[0], tSndBuf.ucText);//   这个gtSolt 那里来的？ 看样子就个公共变量，还有 iSessID .... 等公共变量，如果外部没有保证这些变量 这个 函数不是线程安全的  对于 process 函数 process(...);       // 如果它是放在 这行mutex_unlock() 之前,那么这个 多线程的设计10分不好(比单线程还慢得多) pthread_mutex_unlock() <<=========  //  较好的设计它应该放在 mutex_unlock() 这后  以下是线程池中每个线程的执行函数：  void *thread_routine(void *arg) { 	T_Worker *worker = NULL; 	 	DEBUG_PRINT("starting thread 0x%x\n",pthread_self());  	while(1) 	{ 		pthread_mutex_lock(&(gpPool->queue_lock));  		while(gpPool->cur_queue_size == 0 && !gpPool->shutdown) 		{ 			DEBUG_PRINT("thread 0x%x is waiting\n",pthread_self()); 			pthread_cond_wait(&(gpPool->queue_ready),&(gpPool->queue_lock)); 		} 		 		if(gpPool->shutdown) 		{ 			pthread_mutex_unlock(&(gpPool->queue_lock)); 			DEBUG_PRINT("thread 0x%x will exit\n",pthread_self()); 			pthread_exit(NULL); 		} 		DEBUG_PRINT("thread 0x%x is starting to work\n",pthread_self());  		assert(gpPool->cur_queue_size !=0); 		assert(gpPool->queue_head != NULL);  		gpPool->cur_queue_size--; 		worker = gpPool->queue_head; 		gpPool->queue_head = worker->next;  		pthread_mutex_unlock(&(gpPool->queue_lock));  		(*(worker->process))(worker->arg);//此处执行pool_add_work()添加进队列的回调函数 		free(worker); 		worker = NULL; 	}	 	pthread_exit(NULL); }  gtSlot[N]是全局数组，N就是程序支持的最大的并发个数，每一路并发（就是在程序里做转换）依托一个处理句柄，这个全局数组就是保存对应的N个句柄，每一路发来的包中包含一个iID，在0~N中，由它直接定位哪一个句柄。  通过实验发现，如果Enc，Dec两个处理函数不加锁，转换出来的数据误差较大，但是加了锁会不会大大降低了效率？这两个函数是库里的，我看不到实现，本以为依托于一个处理句柄应该可重入的。我也知道这个问题问您有点不太合适，因为怎么实现的都不知道。

user: user-0
content: 引用 16 楼 dooX8086 的回复:相关楼主还要注意  惊群现象   （pthread_cond_signal  惊群）  process 函数中的 iRet = Enc(gtSlot[iSessID].pHandle, &sBuf[0], tSndBuf.ucText);//   这个gtSolt 那里来的？ 看样子就个公共变量，还有 iSessID .... 等公共变量，如果外部没有保证这些变量 这个 函数不是线程安全的  对于 process 函数 process(...);       // 如果它是放在 这行mutex_unlock() 之前,那么这个 多线程的设计10分不好(比单线程还慢得多) pthread_mutex_unlock() <<=========  //  较好的设计它应该放在 mutex_unlock() 这后 感谢高人继续指导哈 gtSlot是个全局结构数组，这里的iSessID写错了，其实是上边的iID，一路并发对应一个iID，这个转换函数要基于每一路的pHandle。从这些全局变量的作用来看，我要怎么做才是线程安全的？  process在线程中调用，在链表取数据时加解锁，解锁后调用process这个回调，晚上回去我贴下代码，这样设计是否会好一点？

user: user-8
content: 相关楼主还要注意  惊群现象   （pthread_cond_signal  惊群）  process 函数中的 iRet = Enc(gtSlot[iSessID].pHandle, &sBuf[0], tSndBuf.ucText);//   这个gtSolt 那里来的？ 看样子就个公共变量，还有 iSessID .... 等公共变量，如果外部没有保证这些变量 这个 函数不是线程安全的  对于 process 函数 process(...);       // 如果它是放在 这行mutex_unlock() 之前,那么这个 多线程的设计10分不好(比单线程还慢得多) pthread_mutex_unlock() <<=========  //  较好的设计它应该放在 mutex_unlock() 这后

user: user-9
content: 引用 14 楼 Mrzhen009 的回复:[quote=引用 13 楼 zxh707wk 的回复:] 直接上iocp吧 这个不太了解，搜了下是win下的模型吧，现在要求使用Linux。这个是不是与epool差不多？[/quote]还是继续用epoll吧

user: user-0
content: 初始化的时候gpPool->queue_head = NULL

user: user-0
content: 引用 13 楼 zxh707wk 的回复:直接上iocp吧 这个不太了解，搜了下是win下的模型吧，现在要求使用Linux。这个是不是与epool差不多？

user: user-9
content: 直接上iocp吧

user: user-10
content: assert的作用是现计算表达式 expression ，如果其值为假（即为0），那么它先向stderr打印一条出错信息，然后通过调用 abort 来终止程序运行。 崩溃的原因在于断言为假了，建议检查gpPool的初始化及其他操作

user: user-0
content: 引用 8 楼 dooX8086 的回复:这一段是向线程池添加任务的函数，现在总是在这里崩溃  int pool_add(void* (*process)(void *arg), void* arg) { T_Worker *newworker = (T_Worker *)malloc(sizeof(T_Worker)); T_Worker *member = gpPool->queue_head;    // 如果同时入这就有问题 ( 因为你的 queue 是不带头结点的单链表) =====>>>>>>  newworker->process = process; memcpy(newworker->arg,(unsigned char *)arg,512); newworker->next = NULL;  pthread_mutex_lock(&(gpPool->queue_lock));                                                                                      // 应该放到这下面 .......   ////如果程序的重点是数据转换 ... 而转换函数又不是线程安全,(不能多路同进入)。 //// 这个多线程，跑起来还不如单线程快和高效  高人，我还是不太明白T_Worker *member = gpPool->queue_head;这一句 不加锁出错的原因，能不能指点一下？  下面是process回调函数，不知道有没有可重入的风险：  void *process(void *arg) { 	//arg为recvfrom得到的buffer，包含一个头和要转换的数据 	PT_RcvBuf ptRcvBuf = (PT_RcvBuf)arg;  	T_OutBuf tSndBuf; 	short sBuf[PCM_LEN_PER_PACKET]; 	unsigned char ucBuf[EVRC_LOAD_LEN_PER_PACKET]; 	int iRet,iID; 	int sendbytes = 0;  	memset(&tSndBuf, 0, sizeof(T_OutBuf)); 	memset(&sBuf[0], 0, sizeof(sBuf)); 	memset(&ucBuf[0], 0, sizeof(ucBuf));  	iID = (int)(ptRcvBuf->tOutBuf.tHead.ucID); 		 	switch ( (int)(ptRcvBuf->tOutBuf.tHead.ucDirection) ) 	{ 		case ENCODE: 			memcpy(&sBuf[0],ptRcvBuf->tOutBuf.ucText,ENCODE_LEN); 			//编解码函数基于每一路的pHandle指针做处理，调试过程中这里有过报错，因为在lib库中，无法 			//查看，所以有锁，这里略去没写 			iRet = Enc(gtSlot[iSessID].pHandle, &sBuf[0], tSndBuf.ucText);//编码 			if (iRet != 0) 			{ 				printf("Enc Error!\n"); 				return ; 			} 			break;  		case DECODE: 			memcpy(&ucBuf[0],ptRcvBuf->tOutBuf.ucText,DECODE_LEN); 			//编解码函数基于每一路的pHandle指针做处理 			iRet = Dec(gtSlot[iID].pHandle, &ucBuf[0], tSndBuf.ucText);//解码 			if (iRet != 0) 			{ 				printf("Dec Error!\n"); 				return ; 			} 			break;  		default: 			printf("Unknown convert type: %d !\n",(int)(ptRcvBuf->tOutBuf.tHead.ucDirection)); 			return ; 	}  	memcpy( &(tSndBuf.tHead), &(ptRcvBuf->tOutBuf.tHead), sizeof(T_Head) );  	//通过recvfrom把client的sockaddr结构保存下来，并在此把处理后的数据发送回这个IP及PORT 	sendbytes = sendto(giSocketServer,&tSndBuf,sizeof(T_OutBuf),0,(struct sockaddr *)&(ptRcvBuf->tSocketClientAddr),giAddrLen); 	if (sendbytes !=sizeof(T_OutBuf)) 	{ 		perror("sendto"); 	} }