unix环境线程编程练习

    接触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 sleep
pthread_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

#ifndef	TP_H_
#define	TP_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 struct
tp_task* new_task(void (*fun)(void *), void *dat);


// task struct queue
typedef struct tp_task_que
{
	tp_task					*head;
	tp_task					*tail;
	int						size;
}tp_task_que;

// operators of task queue struct
int 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_str		thread_str;
typedef struct thread_pool_str		th_pool_str;

// thread struct
struct thread_info_str
{
	//用于循环控制
	pthread_cond_t		loop_cond;
	pthread_mutex_t		loop_lock;
	//用来同步task_que的操作
	pthread_mutex_t		task_lock;
	tp_task_que			task_que;
	
	pthread_t			t_id;
	th_pool_str			*p_tpool;
	int					is_free;
};

// pool information
struct thread_pool_str
{
	//同步线程和主线程
	pthread_cond_t		tp_cond;
	pthread_mutex_t		tp_lock;
	int					wait_for_ready;
	//线程结构体数组
	thread_str			*th_arr;
	int					th_num;
	int					index;
};


/*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 task
tp_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 tail
int 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 head
tp_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 queue
void 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 process
void* 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 task
		pthread_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 task
		th->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 pool
int 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 pools
void 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 pool
int 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下都通过并正常运行。

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


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.m或d论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 、1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。、资源 5来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。、资 5源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值