关于线程池问题

来源:互联网 发布:淘宝店铺装修代码下载 编辑:程序博客网 时间:2024/06/07 23:36

原文:http://blog.chinaunix.net/uid-26548237-id-3197974.html

线程的取消点:

根据POSIX标准,pthread_join()、pthread_testcancel()、pthread_cond_wait()、 pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及read()、write()等会引起阻塞的系统调用都是Cancelation-point。(但是因与C结合问题read在linux种都不是Cancelation-point;但CANCEL信号会使线程从阻 塞的系统调用中退出,并置EINTR错误码,因此可以在需要作为Cancelation-point的系统调用前后调用 pthread_testcancel(),从而达到POSIX标准所要求的目标,即如下代码段:          

pthread_testcancel();
retcode = read(fd, buffer, length);
pthread_testcancel();


使用前 须判断线程ID的有效性!即判断并保证:thrd != 0 否则有可能会出现“段错误”的异常!

设计注意:

1. 如果线程处于无限循环中,且循环体内没有执行至取消点的必然路径,则线程无法由外部其他线程的取消请求而终止。因此在这样的循环体的必经路径上应该加入pthread_testcancel()调用。

2. 当pthread_cancel()返回时,线程未必已经取消,可能仅仅将请求发送给目标线程,而目标线程目前没有到达取消点,如果要知道线程在何时中止,就需要在取消它之后调用pthread_join()。有一个例外是当线程被detach后,不能这样处理:
           a) 当join一个已经detached的线程时,返回EINVAL;
           b) 如果join后该线程设置为detached,则detach将不起作用。
因此,如果知道一个线程可能会以分离方式运行,就不需要在pthread_cancel()后调用pthread_join()。

 

取消线程函数:

int pthread_cancel(pthread_t thread) 
发送终止信号给thread线程,如果成功则返回0,否则为非0值。发送成功并不意味着thread会终止。

int pthread_setcancelstate(int state, int *oldstate) 
设置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和 PTHREAD_CANCEL_DISABLE,分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行;old_state如果不为NULL则存入原来的Cancel状态以便恢复。

int pthread_setcanceltype(int type, int *oldtype) 
设置本线程取消动作的执行时机,type有两种取值:PTHREAD_CANCEL_DEFFERED 和 PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。

void pthread_testcancel(void) 
检查本线程是否处于Canceld状态,如果是,则进行取消动作,否则直接返回。

检查线程状态:

int pthread_kill(pthread_t thread, int sig
向指定ID的线程发送sig信号,默认整个线程退出。
pthread_kill(threadid, SIGKILL)也一样,他会杀死整个线程。
如果要获得正确的行为,就需要在线程内实现signal(SIGKILL,sig_handler)。
所以,如果int sig的参数不是0,那一定要清楚到底要干什么,而且一定要实现线程的信号处理函数,否则,就会影响整个进程。
那么,如果int sig的参数是0呢,这是一个保留信号,一个作用就是用来判断线程是不是还活着。
我们来看一下pthread_kill的返回值:
线程仍然活着:0
线程已不存在:ESRCH
信号不合法:EINVAL

例子:

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <unistd.h> 
void* func(void *) 

  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); //允许退出线程 
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); //设置立即取消 
  while (1) 
  { 
    //操作 ; 
  } 
  return NULL; 

int main(int argc, char *argv[]) 

  pthread_t thrd; 
  pthread_attr_t attr; 
  pthread_attr_init(&attr); 
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 
  if( pthread_create(&thrd, &attr, func, NULL) ) 
  { 
    perror( "pthread_create error "); 
    exit(EXIT_FAILURE); 
   } 
   if( !pthread_cancel(thrd) )  
   { 
     printf( "pthread_cancel OK\n " ); 
   } 
   sleep( 10 ); 
   return 0; 

上面程序并不会将子线程取消 why?

-------因为没有遇见或是设置引起Cancelation动作的取消点,可以在调用了pthread_cancel函数后,调用pthread_join函数以获得取消点,使线程退出。

***************************************************************************

再看下面一段程序:

pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_testcancel();/*the thread can be killed only here*/
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

这个是代码里面摘录下来的代码,什么情况下 线程能被杀掉呢? 
因为 这段代码 在 线程的循环里面,那每次执行到这段的时候,为什么都没有被杀掉呢?

-------

简单理解就是,两个线程T1和T2,如果T1发送cancel信号给T2,则T2默认会在取消点退出。取消点是固定的地方,只要pthread_join()、pthread_testcancel()、pthread_cond_wait()、 pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及read()、write()等会引起阻塞的系统调用都是Cancelation-point。

假设T2在一个循环中,这个循环中没有取消点,那么怎么办?收到cancel信号也没办法退出。这时就用pthread_testcancel()来创造一个取消点,如果有cancel信号就退出,没有就继续运行。

那么pthread_setcancelstate就比较好理解了,就是设置T2的状态,PTHREAD_CANCEL_ENABLE就是正常处理cancel信号,PTHREAD_CANCEL_DISABLE就是忽略cancel信号。

那么循环体中每次执行到这段的时候,为什么都没有被杀掉呢?
这里的被杀死指的是别的线程发送cancel信号给他,也许这里根本就没发送所以没被杀死。

使用pthread_create创建线程池时线程失败,Resource temporarily unavailable的解决办法

perror打印出的错误原因是:Resource temporarily unavailable:

ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 20
file size (blocks, -f) unlimited
pending signals (-i) 16382
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) unlimited
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

可以看到stack size是10M, 400个线程就需要10*400=4000M,虚拟内存不够用。

解决办法有两种:

1.使用ulimit -s 1024*1024命令,将线程栈大小临时设置成1M,经过试验能同时创建2000个线程了。

2.使用pthread_attr_setstacksize在程序中改变线程栈大小。

 

 

 

 

原创粉丝点击