线程池---linux

linux下线程相关概念以及函数介绍:
互斥锁:
     pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
     pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
     pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
        mutex(互斥锁)是用于保护共享数据结构不受并发修改影响的锁,其还可用于保护程序关键部分。mutex可以有2种状态,unlocked(不被任何线程拥有),locked(被一个线程拥有)。一个mutex不能同时被两个不同的线程所拥有。如果线程A试图去加锁一个已经被线程B锁定的的mutex,则此线程A会阻塞直至线程B对mutex进行解锁操作后。
    mutex操作函数:
     int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
          pthread_mutex_init()函数使用mutexattr属性初始化mutex指针所指向的mutex,如果mutexattr=NULL,则使用默认属性初始化mutex.linux线程只支持一个mutex属性,此属性的种类可以是fast,recursive,error checking。属性的种类决定此mutex是否可以被已经拥有此mutex的线程再次加锁。默认属性的种类是fast.
        mutex也可使用 PTHREAD_MUTEX_INITIALIZER直接进行静态初始化为mutex属性是fast的互斥锁,也可使用PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP直接进行静态初始化为mutex属性是recursive类型的互斥锁,也可使用PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP直接进行静态初始化为mutex属性是error checking类型的互斥锁。
     int pthread_mutex_lock(pthread_mutex_t *mutex);
        锁定mutex.如果mutex当前是unlocked状态,则mutex的状态将由调用 pthread_mutex_lock的线程修改为locked,且此时 pthread_mutex_lock立即返回; 如果mutex当前是locked状态(已经由别的线程加锁),则 pthread_mutex_lock挂起调用 pthread_mutex_lock的线程直至,mutex被解锁(默认行为)。
          如果mutex当前是locked状态(已经由别的线程加锁),则 pthread_mutex_lock的行为由mutex的属性所决定。
       mutex的属性是fast:调用 pthread_mutex_lock会挂起直至mutex被解锁。 从而导致调用 pthread_mutex_lock的线程发生死锁。
       mutex的属性是 recursive : pthread_mutex_lock会成功并立即返回,并记录调用 pthread_mutex_lock锁定互斥锁的次数。在mutex返回到解锁状态前,必须执行相同次数的 pthread_mutex_unlock.
       mutex的属性是 error checking : pthread_mutex_lock会带有错误码EDEADLK立即返回。
     int pthread_mutex_trylock(pthread_mutex_t *mutex);
        pthr ead_mutex_trylock与 pthread_mutex_lock是相同的,如果互斥锁已经被另外的线程锁定,pthread_mutex_trulock不会阻塞线程,而是立即返回,并返回错误代码EBUSY.
     int pthread_mutex_unlock(pthread_mutex_t *mutex);
         pthread_mutex_unlock解锁给定的mutex.在执行pthread_mutex_unlock的时候。所给定的mutex假定为已经被调用pthread_mutex_unlock的线程锁定。如果mutex的属性是fast,pthread_mutex_unlock总是返回unlocked状态的mutex;如果mutex的属性是recursive,pthread_mutex_unlock会降低mutex被锁定的次数,只有当此个数为0的时候,mutex才真正被解锁。在mutex的属性是error checking和recursive的时候,pthread_mutex_unlock会在运行时检查mutex是否锁定,并且判断mutex是否被调用pthread_mutex_unlock的同一线程锁定,之后才会调用pthread_mutex_unlock。如果条件都不满足,则返回错误代码。mutex的属性是fast在调用pthread_mutex_unlock的不会做这些检查,因此允许被锁定的互斥锁由其所有者以外的线程解锁。这是不可移植,不能依赖。
     int pthread_mutex_destroy(pthread_mutex_t *mutex);
          pthread_mutex_destroy销毁mutex,释放资源。在调用此函数前mutex必须是unlock的。在linux线程中,mutex与资源无关。pthread_mutex_destroy实际上只是检查mutex是否被解锁。
取消  :  
    互斥锁的操作函数中没有取消操作。pthread_mutex_lock也不是。尽管此函数可以挂起一个线程来执行任意时间,这种情况下互斥锁的取消是可预测的,允许取消处理去精确地解锁那些需要在程序停止前解锁的互斥锁,。。因此先吃使用延迟取消使得不能在长时间保留互斥锁。
异步信号安全:    
    互斥操作函数不是异步信号安全的,这意味着它们不应该在信号处理程序中调用。特别是在信号处理程序中去调用pthread_mutex_lock或者pthread_mutex_unlock,这样可能会造成线程死锁。
返回值:
        pthread_mutex_init总是返回0,其他函数在执行成功的时候返回0,执行失败的时候返回错误码。
错误码
函数错误码说明
pthread_mutex_lockEINVALmutex未正确初始化
EDEADLKmutex(只有初始化为error check类型)已经加锁
pthread_mutex_trylockEBUSYmutex不能获取,因为其已经被锁定
EINVALmutex未正确初始化
pthread_mutex_unlockEINVALmutex未正确初始化
EPERM调用线程不是锁定mutex的线程(mutex初始化为error check)
pthread_mutex_destoryEBUSYmutex已经被锁定
条件变量:
        pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    条件变量是一种同步机制。其可以使线程暂停执行并释放cpu时间直到共享数据上的某个判断条件得以满足。条件变量的基本操作:当待判断的条件得以满足的时候向条件变量发送信号,然后等待条件变量,原来暂停的线程得以再次执行,直到另一个条件。为防止竞争,条件变量必须和互斥锁相关联。
       int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
       pthread_cond_init  使用cond_attr属性初始化条件变量cond。如果cond_attr是NULL则使用默认属性初始化cond.linux线程对于条件变量不支持任何属性,因此linux在实际处理的时候是忽略属性的。pthread_cond_t也可使用PTHREAD_COND_INITIALIZER去进行静态初始化。
        int pthread_cond_signal(pthread_cond_t *cond);
          pthread_cond_signal启动一个正在等待条件变量cond的线程。如果没有线程在等待cond则不会发生任何事。如果有多个线程同时在等待cond,实际上只有一个线程启动,但是并不指定哪一个。
       int pthread_cond_broadcast(pthread_cond_t *cond);
          pthread_cond_broadcast启动所有正在等待条件变量cond的线程。如果没有线程在等待cond则不会发生任何事。
       int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
         pthread_cond_wait自动解锁mutex(等同于调用了pthread_mutex_unlock)并等待cond信号被触发(signal)。在调用此函数后,且cond未触发的时候,调用此函数的线程会阻塞,且不会占用任何CPU时间。在调用pthread_cond_wait之前mutex必须是加锁的。在cond条件触发的时候并且在返回到调用线程前,pthread_cond_wait会再次为mutex加锁。解锁以及线程挂起等待条件变量的操作是原子的,因此如果所有线程总是在发出条件变量信号前对互斥锁加锁,就保证了在线程锁定互斥锁和等待条件变量之间,条件是不能被标记的。这就意味着开发者在调用pthread_cond_wait后的处理代码中仍需要添加与之对应的mutex的解锁代码,否则会造成线程死锁。
       int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
      pthread_cond_timedwait和 pthread_cond_wait一样会 自动解锁mutex,并等待cond。但是其使用abstime限制了等待cond的时间。如果条件cond在abstime所设置的事件内未触发, pthread_cond_timedwait会再次加锁mutex并返回错误码ETIMEDOUT。 abstime参数指定了一个绝对时间,使用time(),gettimeofday()去获取此时间是相同的,如果abstime=0,则代表了1970年1月1日00:00:00
       int pthread_cond_destroy(pthread_cond_t *cond);
      pthread_cond_destroy销毁一个条件变量cond.如果cond占有资源则释放资源。在调用此函数前必须保证没有线程在等待cond这个条件变量。在linux线程实现中没有cond是没有资源占用的。因此在linux下 pthread_cond_destroy只是在判断是否有线程在等待此条件变量cond.
取消  :   
        pthread_cond_timedwait()和 pthread_cond_wait ()是取消点。如果一个线程在挂起在 pthread_cond_timedwait, pthread_cond_wait  这些函数的时候被取消,则线程立即恢复执行,然后再次将mutex加锁到  这些函数,最后执行取消。因此清理处理程序必须确保mutex是在加锁状态。
异步信号安全:    
     互斥操作函数不是异步信号安全的,这意味着它们不应该在信号处理程序中调用。特别是在信号处理程序中去调用pthread_cond_signal或者pthread_cond_broadcast,这样可能会造成线程死锁。
返回值:
          所有函数在执行成功的时候返回0,执行失败的时候返回错误码。
错误:
函数错误码说明
pthread_cond_timedwaitETIMEDOUT直到abstime所指定的时间,cond还未被触发
EINTRpthread_cond_timedwait被信号打断
pthread_cond_destroyEBUSY有线程正在等待cond条件
 
 
实例源码一:
 1 /************************************threadpool.h***************************************************/
 2 #ifndef __THREADPOOL_H_
 3 #define __THREADPOOL_H_
 4 typedef struct threadpool_t threadpool_t;
 5 /*创建线程池*/
 6 threadpool_t *threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size);
 7 /*释放线程池*/
 8 int threadpool_free(threadpool_t *pool);
 9 /*销毁线程池*/
10 int threadpool_destroy(threadpool_t *pool);
11 /*管理线程*/
12 void *admin_thread(void *threadpool);
13 /*线程是否存在*/
14 //int is_thread_alive(pthread_t tid);
15 /*工作线程*/
16 void *threadpool_thread(void *threadpool);
17 /*向线程池的任务队列中添加一个任务*/
18 int threadpool_add_task(threadpool_t *pool, void *(*function)(void *arg), void *arg);
19 #endif

 

  1 /************************************threadpool.c***************************************************/
  2 #include "threadpool.h"
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <pthread.h>
  6 #include <signal.h>
  7 #include <assert.h>
  8 #include <string.h>
  9 #include <errno.h>
 10 
 11 #define DEFAULT_TIME 1            /*默认时间10s*/
 12 #define MIN_WAIT_TASK_NUM 10       /*当任务数超过了它,就该添加新线程了*/
 13 #define DEFAULT_THREAD_NUM 10      /*每次创建或销毁的线程个数*/
 14 #define true 1
 15 #define false 0
 16 
 17 
 18 /*任务*/
 19 typedef struct {
 20    void *(*function)(void *);
 21    void *arg;
 22 } threadpool_task_t;
 23 
 24 /*线程池管理*/
 25 struct threadpool_t{
 26    pthread_mutex_t lock;                 /* 锁住整个结构体 */
 27    pthread_mutex_t thread_counter;       /* 用于使用忙线程数时的锁 */
 28    pthread_cond_t  queue_not_full;       /* 条件变量,任务队列不为满 */
 29    pthread_cond_t  queue_not_empty;      /* 任务队列不为空 */
 30 
 31    pthread_t *threads;                   /* 存放线程的tid,实际上就是管理了线 数组 */
 32    pthread_t admin_tid;                  /* 管理者线程tid */
 33    threadpool_task_t *task_queue;        /* 任务队列 */
 34 
 35    /*线程池信息*/
 36    int min_thr_num;                      /* 线程池中最小线程数 */
 37    int max_thr_num;                      /* 线程池中最大线程数 */
 38    int live_thr_num;                     /* 线程池中存活的线程数 */
 39    int busy_thr_num;                     /* 忙线程,正在工作的线程 */
 40    int wait_exit_thr_num;                /* 需要销毁的线程数 */
 41 
 42    /*任务队列信息*/
 43    int queue_front;                      /* 队头 */
 44    int queue_rear;                       /* 队尾 */
 45    int queue_size; 
 46  
 47    /* 存在的任务数 */
 48    int queue_max_size;                   /* 队列能容纳的最大任务数 */
 49 
 50    /*状态*/
 51    int shutdown;                         /* true为关闭 */
 52 };
 53 
 54 
 55 /*  函数原型  */
 56 
 57 /*创建线程池*/
 58 threadpool_t *threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size);
 59 /*释放线程池*/
 60 int threadpool_free(threadpool_t *pool);
 61 /*销毁线程池*/
 62 int threadpool_destroy(threadpool_t *pool);
 63 /*管理线程*/
 64 void *admin_thread(void *threadpool);
 65 /*线程是否存在*/
 66 int is_thread_alive(pthread_t tid);
 67 /*工作线程*/
 68 void *threadpool_thread(void *threadpool);
 69 /*向线程池的任务队列中添加一个任务*/
 70 int threadpool_add_task(threadpool_t *pool, void *(*function)(void *arg), void *arg);
 71 
 72 /*           */
 73 
 74 
 75 /*创建线程池*/
 76 threadpool_t *
 77 threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size)
 78 {
 79    int i;
 80    threadpool_t *pool = NULL;
 81    do
 82    {
 83       if ((pool=(threadpool_t *)malloc(sizeof(threadpool_t))) == NULL)
 84       {
 85         printf("malloc threadpool false; \n");
 86     break;   
 87       }
 88       /*信息初始化*/
 89       pool->min_thr_num = min_thr_num;
 90       pool->max_thr_num = max_thr_num;
 91       pool->busy_thr_num = 0;
 92       pool->live_thr_num = min_thr_num;
 93       pool->wait_exit_thr_num = 0;
 94       pool->queue_front = 0;
 95       pool->queue_rear = 0;
 96       pool->queue_size = 0;
 97       pool->queue_max_size = queue_max_size;
 98       pool->shutdown = false;
 99    
100       /*根据最大线程数,给工作线程数组开空间,清0*/
101       pool->threads = (pthread_t *)malloc(sizeof(pthread_t)*max_thr_num);//根据线程池中最多容纳的线程数创建线程数组
102       if (pool->threads == NULL)
103       {
104          printf("malloc threads false;\n");
105      break;
106       }
107       memset(pool->threads, 0, sizeof(pthread_t)*max_thr_num);
108 
109       /*队列开空间*/
110       pool->task_queue = 
111       (threadpool_task_t *)malloc(sizeof(threadpool_task_t)*queue_max_size);//根据人物队列中最多容纳的任务数创建线任务数组
112       if (pool->task_queue == NULL)
113       {
114          printf("malloc task queue false;\n");
115      break;
116       }
117 
118       /*初始化互斥锁和条件变量*/
119       if ( pthread_mutex_init(&(pool->lock), NULL) != 0           ||
120            pthread_mutex_init(&(pool->thread_counter), NULL) !=0  || 
121        pthread_cond_init(&(pool->queue_not_empty), NULL) !=0  ||
122        pthread_cond_init(&(pool->queue_not_full), NULL) !=0)
123       {
124          printf("init lock or cond false;\n");
125          break;
126       }
127 
128       /*启动min_thr_num个工作线程*/
129       for (i=0; i<min_thr_num; i++)
130       {
131          /*pool指向当前线程池*/
132          pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool);///依据线程池中的最小线程数去创建线程
133           printf("start thread 0x%x... \n", (unsigned int)pool->threads[i]);
134       }
135       /*管理者线程*/
136       pthread_create(&(pool->admin_tid), NULL, admin_thread, (void *)pool);///创建管理者线程
137 
138       return pool;//返回创建好的线程池
139    } while(0);
140 
141    /*释放pool的空间*/
142    threadpool_free(pool);
143    return NULL;
144 }
145 
146 /*释放线程池*/
147 int 
148 threadpool_free(threadpool_t *pool)
149 {
150    if (pool == NULL)
151    {
152      return -1;
153    }
154 
155    if (pool->task_queue)
156    {
157       free(pool->task_queue);
158    }
159    if (pool->threads)
160    {
161       free(pool->threads);
162       pthread_mutex_lock(&(pool->lock));               /*先锁住再销毁*/
163       pthread_mutex_destroy(&(pool->lock));
164       pthread_mutex_lock(&(pool->thread_counter));
165       pthread_mutex_destroy(&(pool->thread_counter));
166       pthread_cond_destroy(&(pool->queue_not_empty));
167       pthread_cond_destroy(&(pool->queue_not_full));
168    }
169    free(pool);
170    pool = NULL;
171 
172    return 0;
173 }
174 
175 /*销毁线程池*/
176 int 
177 threadpool_destroy(threadpool_t *pool)
178 {
179    int i;
180    if (pool == NULL)
181    {
182      return -1;
183    }
184    pool->shutdown = true;
185 
186    /*销毁管理者线程*/
187    pthread_join(pool->admin_tid, NULL);
188 
189    //通知所有线程去自杀(在自己领任务的过程中)
190    for (i=0; i<pool->live_thr_num; i++)
191    {
192      pthread_cond_broadcast(&(pool->queue_not_empty));
193    }
194 
195    /*等待线程结束 先是pthread_exit 然后等待其结束*/
196    for (i=0; i<pool->live_thr_num; i++)
197    {
198      pthread_join(pool->threads[i], NULL);
199    }
200 
201    threadpool_free(pool);
202    return 0;
203 }
204 
205 /*管理线程*/
206 void *
207 admin_thread(void *threadpool)
208 {
209    int i;
210    threadpool_t *pool = (threadpool_t *)threadpool;
211    while (!pool->shutdown)
212    {
213       printf("admin -----------------\n");
214       sleep(DEFAULT_TIME);                             /*隔一段时间再管理*/
215       pthread_mutex_lock(&(pool->lock));               /*加锁*/ 
216       int queue_size = pool->queue_size;               /*任务数*/
217       int live_thr_num = pool->live_thr_num;           /*存活的线程数*/
218       pthread_mutex_unlock(&(pool->lock));             /*解锁*/
219       
220       pthread_mutex_lock(&(pool->thread_counter));
221       int busy_thr_num = pool->busy_thr_num;           /*忙线程数*/  
222       pthread_mutex_unlock(&(pool->thread_counter));
223 
224       printf("admin busy live -%d--%d-\n", busy_thr_num, live_thr_num);
225       /*创建新线程 实际任务数量大于 最小正在等待的任务数量,存活线程数小于最大线程数*/
226       if (queue_size >= MIN_WAIT_TASK_NUM && live_thr_num <= pool->max_thr_num)
227       {
228          printf("admin add-----------\n");
229          pthread_mutex_lock(&(pool->lock));
230          int add=0;
231 
232          /*一次增加 DEFAULT_THREAD_NUM 个线程*/
233      for (i=0; i<pool->max_thr_num && add<DEFAULT_THREAD_NUM 
234          && pool->live_thr_num < pool->max_thr_num; i++)
235      {
236         if (pool->threads[i] == 0 || !is_thread_alive(pool->threads[i]))
237         {
238            pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool);
239            add++;
240            pool->live_thr_num++;
241            printf("new thread -----------------------\n");
242         }
243      }
244 
245      pthread_mutex_unlock(&(pool->lock));
246       }
247 
248       /*销毁多余的线程 忙线程x2 都小于 存活线程,并且存活的大于最小线程数*/
249       if ((busy_thr_num*2) < live_thr_num  &&  live_thr_num > pool->min_thr_num)
250       {
251         // printf("admin busy --%d--%d----\n", busy_thr_num, live_thr_num);
252          /*一次销毁DEFAULT_THREAD_NUM个线程*/
253      pthread_mutex_lock(&(pool->lock));
254          pool->wait_exit_thr_num = DEFAULT_THREAD_NUM;
255      pthread_mutex_unlock(&(pool->lock));
256 
257      for (i=0; i<DEFAULT_THREAD_NUM; i++)
258      {
259         //通知正在处于空闲的线程,自杀
260         pthread_cond_signal(&(pool->queue_not_empty));
261         printf("admin cler --\n");
262      }
263       }
264    }
265   
266    return NULL;
267 }
268 /*线程是否存活*/
269 int 
270 is_thread_alive(pthread_t tid)
271 {
272    int kill_rc = pthread_kill(tid, 0);     //发送0号信号,测试是否存活
273    if (kill_rc == ESRCH)  //线程不存在
274    {
275       return false;
276    }
277    return true;
278 }
279 
280 /*工作线程*/
281 void *
282 threadpool_thread(void *threadpool)
283 {
284   threadpool_t *pool = (threadpool_t *)threadpool;
285   threadpool_task_t task;
286 
287   while (true)
288   {
289     pthread_mutex_lock(&(pool->lock));//为线程池上锁
290 
291     //无任务则阻塞在 任务队列不为空 上,有任务则跳出
292     while ((pool->queue_size == 0) && (!pool->shutdown))
293     { 
294        printf("thread 0x%x is waiting \n", (unsigned int)pthread_self());
295        pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock));
296 
297        //判断是否需要清除线程,自杀功能
298        if (pool->wait_exit_thr_num > 0)
299        {
300           pool->wait_exit_thr_num--;
301           //判断线程池中的线程数是否大于最小线程数,是则结束当前线程
302       if (pool->live_thr_num > pool->min_thr_num)
303       {
304         printf("thread 0x%x is exiting \n", (unsigned int)pthread_self());
305         pool->live_thr_num--;
306         pthread_mutex_unlock(&(pool->lock));
307         pthread_exit(NULL);//结束线程
308       }
309        }
310     }
311 
312     //线程池开关状态
313     if (pool->shutdown) //关闭线程池
314     {
315        pthread_mutex_unlock(&(pool->lock));
316        printf("thread 0x%x is exiting \n", (unsigned int)pthread_self());
317        pthread_exit(NULL); //线程自己结束自己
318     }
319 
320     //否则该线程可以拿出任务
321     task.function = pool->task_queue[pool->queue_front].function; //出队操作
322     task.arg = pool->task_queue[pool->queue_front].arg;
323 
324     pool->queue_front = (pool->queue_front + 1) % pool->queue_max_size;  //环型结构
325     pool->queue_size--;
326 
327     //通知可以添加新任务
328     pthread_cond_broadcast(&(pool->queue_not_full));
329     
330     //释放线程锁
331     pthread_mutex_unlock(&(pool->lock));
332     
333     //执行刚才取出的任务
334     printf("thread 0x%x start working \n", (unsigned int)pthread_self());
335     pthread_mutex_lock(&(pool->thread_counter));            //锁住忙线程变量
336     pool->busy_thr_num++;
337     pthread_mutex_unlock(&(pool->thread_counter));
338 
339     (*(task.function))(task.arg);                           //执行任务
340 
341     //任务结束处理
342     printf("thread 0x%x end working \n", (unsigned int)pthread_self());
343     pthread_mutex_lock(&(pool->thread_counter));
344     pool->busy_thr_num--;
345     pthread_mutex_unlock(&(pool->thread_counter));
346   }
347 
348   pthread_exit(NULL);
349 }
350 
351 /*向线程池的任务队列中添加一个任务*/
352 int 
353 threadpool_add_task(threadpool_t *pool, void *(*function)(void *arg), void *arg)
354 {
355    pthread_mutex_lock(&(pool->lock));
356 
357    /*如果队列满了,调用wait阻塞*/
358    while ((pool->queue_size == pool->queue_max_size) && (!pool->shutdown))
359    {
360       pthread_cond_wait(&(pool->queue_not_full), &(pool->lock));
361    }
362    /*如果线程池处于关闭状态*/
363    if (pool->shutdown)
364    {
365       pthread_mutex_unlock(&(pool->lock));
366       return -1;
367    }
368 
369    /*清空工作线程的回调函数的参数arg*/
370    if (pool->task_queue[pool->queue_rear].arg != NULL)
371    {
372       free(pool->task_queue[pool->queue_rear].arg);
373       pool->task_queue[pool->queue_rear].arg = NULL;
374    }
375    
376    /*添加任务到任务队列*/
377    pool->task_queue[pool->queue_rear].function = function;
378    pool->task_queue[pool->queue_rear].arg = arg;
379    pool->queue_rear = (pool->queue_rear + 1) % pool->queue_max_size;  /* 逻辑环  */
380    pool->queue_size++;
381 
382    /*添加完任务后,队列就不为空了,唤醒线程池中的一个线程*/
383    pthread_cond_signal(&(pool->queue_not_empty));
384    pthread_mutex_unlock(&(pool->lock));
385 
386    return 0;
387 }

 

实例源码二:
    
 1 #include <pthread.h>
 2 #include <unistd.h>
 3  
 4 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
 5 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
 6  
 7 struct node {
 8 int n_number;
 9 struct node *n_next;
10 } *head = NULL;
11  
12 /*[thread_func]*/
13 static void cleanup_handler(void *arg)
14 {
15     printf("Cleanup handler of second thread./n");
16     free(arg);
17     (void)pthread_mutex_unlock(&mtx);
18 }
19 static void *thread_func(void *arg)
20 {
21     struct node *p = NULL;
22  
23     pthread_cleanup_push(cleanup_handler, p);
24     while (1) {
25     pthread_mutex_lock(&mtx);//这个mutex主要是用来保证pthread_cond_wait的并发性
26     while (head == NULL)   {/*这个while要特别说明一下,单个pthread_cond_wait功能很完善,为何这里要有一个while (head == NULL)呢?因为pthread_cond_wait里的线程可能会被意外唤醒,如果这个时候head != NULL,则不是我们想要的情况。这个时候,应该让线程继续进入pthread_cond_wait*/
27    pthread_cond_wait(&cond, &mtx);/*pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);,再读取资源*/
28 //用这个流程是比较清楚的/*block-->unlock-->wait() return-->lock*/
29     }
30         p = head;
31         head = head->n_next;
32         printf("Got %d from front of queue/n", p->n_number);
33         free(p);
34         pthread_mutex_unlock(&mtx);             //临界区数据操作完毕,释放互斥锁
35     }
36     pthread_cleanup_pop(0);
37     return 0;
38 }
39  
40 int main(void)
41 {
42     pthread_t tid;
43     int i;
44     struct node *p;
45     pthread_create(&tid, NULL, thread_func, NULL);   //子线程会一直等待资源,类似生产者和消费者,但是这里的消费者可以是多个消费者,而不仅仅支持普通的单个消费者,这个模型虽然简单,但是很强大
46     /*[tx6-main]*/
47     for (i = 0; i < 10; i++) {
48         p = malloc(sizeof(struct node));
49         p->n_number = i;
50         pthread_mutex_lock(&mtx);             //需要操作head这个临界资源,先加锁,
51         p->n_next = head;
52         head = p;
53         pthread_cond_signal(&cond);
54         pthread_mutex_unlock(&mtx);           //解锁
55         sleep(1);
56     }
57     printf("thread 1 wanna end the line.So cancel thread 2./n");
58     pthread_cancel(tid);             //关于pthread_cancel,有一点额外的说明,它是从外部终止子线程,子线程会在最近的取消点,退出线程,而在我们的代码里,最近的取消点肯定就是pthread_cond_wait()了。关于取消点的信息,有兴趣可以google,这里不多说了
59     pthread_join(tid, NULL);
60     printf("All done -- exiting/n");
61     return 0;
62 }

 

 
 
 
 

转载于:https://www.cnblogs.com/spite/p/9476046.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值