unix环境线程编程练习

来源:互联网 发布:java方法的声明 编辑:程序博客网 时间:2024/06/05 05:41

    接触Unix环境的posix线程有一段时间了,始终有些问题莫名其妙,比如互斥锁……

    在Windows下就发现有这样的现象:

共享的数据:
int a = 0;

//线程1执行:
EnterCriticalSection(&lock);
for(;;){
 cout<<a<<endl;
 Sleep(100);
}
LeaveCriticalSection(&lock);

//线程2执行:
for(;;)
 a++;

程序输出中a被线程2修改,线程1连续打印递增的结果。不过当时没管他。

    最近在Linux下写一个线程池,可是遇到一个问题解决不了,总是卡死,朋友说是我逻辑上有问题,于是花心思写了一些测试程序,就是想搞清楚互斥锁。我又把上面的情况移到Linux下,看到一样的情况。这下麻烦了,所有的资料都同一个说法:互斥锁(或临界区)是用来保护共享内存的。但是这种情况下怎么保护?没有资料来解释一下。

    后来做了这样的测试:

pthread_mutex_t locker = /*初始化锁*/;void* thread_proc(void *){//线程函数体printf("thread %d sleep...\n",arg);pthread_mutex_lock(&lock);/*这里锁定*/sleep(1); //什么也不干,just sleeppthread_mutex_unlock(&lock);//*这里解锁*/printf("thread %d wake up",arg);//提示线程已经解锁... //这里不重要return NULL;}

在主函数里创建5个线程,打印结果比较有趣,信号量设置初始资源为1时的情况相似:

把printf("thread %d sleep...\n",arg);放到pthread_mutex_lock(&lock);后面,就是这样:

有时有交错:

看来线程是在pthread_mutex_lock(&lock);这里阻塞了,只等pthread_mutex_unlock(&lock);之后才放行。初步分析,这些互斥锁的作用原理就好比一扇门,一次只能一个线程放行。而且和共享的内存没任何关系。到FreeBSD下重新编译一下,结果一样,我就不贴出来了。

    感觉被误导了,不知道我这样分析对不对,作用原理应该就是一个通道有两个门,一个进一个出,通道里是操作共享数据的地方,只能有一个线程在通道里;而信号量可以让多个线程同时在通道里,出一个,才能进一个。如果我理解的正确,那我应该注意两点:尽量别把情况搞复杂了,不然卡住了就不好分析了;一个锁不要用在两个地方。

    下面是最后的线程池代码:

声明:threadpool.h

#ifndefTP_H_#defineTP_H_#include <stdlib.h>#include <sys/types.h>#include <pthread.h>/****************************************//*task and task queue*/typedef struct tp_task{void*data;void(*operate)(void *);struct tp_task*next;}tp_task;// operators of task structtp_task* new_task(void (*fun)(void *), void *dat);// task struct queuetypedef struct tp_task_que{tp_task*head;tp_task*tail;intsize;}tp_task_que;// operators of task queue structint push_task( tp_task_que *tq, tp_task *pt);tp_task* pop_task(tp_task_que *tq);void clear_task_que(tp_task_que *tq);/*********************************************//*线程池*/typedef struct thread_info_strthread_str;typedef struct thread_pool_strth_pool_str;// thread structstruct thread_info_str{//用于循环控制pthread_cond_tloop_cond;pthread_mutex_tloop_lock;//用来同步task_que的操作pthread_mutex_ttask_lock;tp_task_quetask_que;pthread_tt_id;th_pool_str*p_tpool;intis_free;};// pool informationstruct thread_pool_str{//同步线程和主线程pthread_cond_ttp_cond;pthread_mutex_ttp_lock;intwait_for_ready;//线程结构体数组thread_str*th_arr;intth_num;intindex;};/*thread函数*/void* thread_proc(void *arg);/*threadpool接口*/int init_tpool(th_pool_str *tpool, int num);void close_tpool(th_pool_str *tpool);int submit_task(th_pool_str *tpool, void (*operate)(void *), void *data );#endif

实现:threaadpool.c


#include <stdio.h>#include <signal.h>#include <assert.h>#include "threadpool.h"#ifndef NDEBUG#define PRTDEBUG(str)puts(str)#else#define PRTDEBUG(str)#endif/***task queue***/// create a new tasktp_task* new_task(void (*op)(void *), void *dat){if (NULL!=op){tp_task *pt = (tp_task *)malloc(sizeof(tp_task));if (NULL!=pt){pt->data = dat;pt->operate = op;pt->next = NULL;return pt;}}return NULL;}// push node at tailint push_task( tp_task_que *tq, tp_task *pt){assert(NULL!=tq);if (0==tq->size){tq->head = tq->tail = pt;tq->size = 1;}else{tq->tail->next = pt;tq->tail = pt;tq->size++;}return 0;}// pop node at headtp_task* pop_task(tp_task_que *tq){assert(NULL!=tq);tp_task *tmp;if (0==tq->size){return NULL;}else{tmp = tq->head;tq->head = tmp->next;tq->size--;if (0==tq->size){tq->tail = NULL;}return tmp;}}// clear task queuevoid clear_task_que(tp_task_que *tq){assert(NULL!=tq);if (NULL!=tq && tq->size>0){tp_task *tmp1 = tq->head, *tmp2;do{tmp2 = tmp1;tmp1 = tmp1->next;free(tmp2);} while (NULL!=tmp1);tq->size = 0;tq->head = NULL;tq->tail = NULL;}}///////////////////////////////////////////////// thread processvoid* thread_proc(void *arg){thread_str *th = (thread_str *)arg;th_pool_str *tpool = th->p_tpool;pthread_mutex_lock(&tpool->tp_lock);tpool->wait_for_ready = 0;pthread_cond_signal(&tpool->tp_cond);pthread_mutex_unlock(&tpool->tp_lock);tp_task *tmp;while (1){// loop waitinng taskpthread_mutex_lock(&th->loop_lock);if (0==(th->task_que.size))pthread_cond_wait(&th->loop_cond, &th->loop_lock);pthread_mutex_unlock(&th->loop_lock);PRTDEBUG("actived");// loop doing taskth->is_free = 0;for (;;){pthread_mutex_lock(&th->task_lock);tmp = pop_task(&th->task_que);pthread_mutex_unlock(&th->task_lock);if (NULL==tmp)break;(tmp->operate)(tmp->data);}th->is_free = 1;}pthread_exit(0);}// initial poolint init_tpool(th_pool_str *tpool, int num){if (0!=pthread_cond_init(&tpool->tp_cond, NULL)){fputs("pthread_cond_init", stderr);return -1;}if (0!=pthread_mutex_init(&tpool->tp_lock, NULL)){fputs("pthread_mutex_init", stderr);return -1;}thread_str *th_arr = (thread_str *)malloc(num * sizeof(thread_str));if (NULL==th_arr){fputs("malloc", stderr);return -1;}int i, ret;for (i = 0; i < num; i++){th_arr[i].task_que.head = NULL;th_arr[i].task_que.tail = NULL;th_arr[i].task_que.size = 0;ret = (pthread_cond_init(&th_arr[i].loop_cond, NULL) != 0) ||(pthread_mutex_init(&th_arr[i].loop_lock, NULL) != 0) ||(pthread_mutex_init(&th_arr[i].task_lock, NULL) != 0);if (ret){fputs("thread_str initial", stderr);break;}if (pthread_create(&th_arr[i].t_id, NULL, thread_proc, &th_arr[i])){perror("pthread_create");break;}th_arr[i].is_free = 0;th_arr[i].p_tpool = tpool;tpool->wait_for_ready = 1;pthread_mutex_lock(&tpool->tp_lock);if (tpool->wait_for_ready)pthread_cond_wait(&tpool->tp_cond, &tpool->tp_lock);pthread_mutex_unlock(&tpool->tp_lock);}if (i<num){for (; i>=0; --i){pthread_kill(th_arr[i].t_id,SIGKILL);}free(th_arr);return -1;}tpool->th_arr = th_arr;tpool->th_num = num;tpool->index = 0;return 0;}// close all threads of poolsvoid close_tpool(th_pool_str *tpool){int i;for (i = 0; i < (tpool->th_num); i++){pthread_kill(tpool->th_arr[i].t_id, SIGKILL);clear_task_que(&tpool->th_arr[i].task_que);}free(tpool->th_arr);PRTDEBUG("destroy thread pool\n");}// submit one task to thread poolint submit_task(th_pool_str *tpool, void (*operate)(void *), void *data ){if (NULL==tpool)return -1;thread_str *th = &tpool->th_arr[tpool->index];int ret;tp_task *ptask = new_task(operate, data);pthread_mutex_lock(&th->task_lock);ret = push_task(&th->task_que, ptask);pthread_mutex_unlock(&th->task_lock);if (ret)return -1;pthread_mutex_lock(&th->loop_lock);pthread_cond_signal(&th->loop_cond);pthread_mutex_unlock(&th->loop_lock);tpool->index++;if ( (tpool->index) >= (tpool->th_num) )               tpool->index = 0;return 0;} 

使用测试文件:test.c


#include <stdio.h>#include <stdlib.h>#include <string.h>#include "threadpool.h"void fun(void *arg){printf("task %d start...\n",arg);sleep(1);printf("task %d complite!\n",arg);}int main (int argc, char *argv[]){long i,n,m;scanf("%d%d",&n,&m);getchar();th_pool_str tpool;if (init_tpool(&tpool, n)){fputs("init_tpool",stderr);_exit(1);}printf("create %d thread in pool\n",i);for (i = 1; i <= m; i++){submit_task(&tpool, fun, (void*)i);}printf("submit end\n");getchar();puts("at the end\n");close_tpool(&tpool);_exit(0);} 

在Linux和FreeBSD下都通过并正常运行。

使用方法只有三个函数,功能很少,但是方便的。


0 0
原创粉丝点击