多线程(五):线程多次汇合控制

这终于是最后一个实验作业了......因为做课设,所以拖了好几天,到现在才写。好了不多说废话了,进入正题。。

本次实验的流程大概是任务一->线程汇合->任务二->线程汇合->从头开始。

其中任务一仍然是判断素数还是合数然后输出到output中,任务二是对input重新赋值然后清理output(清理这部分我没弄)。

还是先贴出代码:

#include <stdio.h>
#include <pthread.h>


typedef struct myTestType
{
	int threadID;
	int dataNum;
	int repeatNum;

	int *threadNum;
	int *input;
	int *output;
	int *index;
	int *endFlag;
	int *repeatFlag;
	pthread_mutex_t *pMutIndex;
}myTest;

int calculate(int input) {
	int i;
	int output = 0;
	for(i=2; i<input/2; i++) {
		if(input % i == 0) {
			output = 1;
			break;
		}
	}
	if(output == 0)
	{
		sleep(1);
	}
	return output;
}

int generate(int index) {
	int input;
	if(index % 4 == 0)
		input = (1 << (index%30)) + 1;
	else
		input = (7 << (index%16)) + 1;
	return input;
}




void thread(myTest * pMyTest) {
	printf("Begin threadID=%u run!\n", pMyTest->threadID);
	int index, rindex, input, output;
	int threadID = pMyTest->threadID;
	int dataNum = pMyTest->dataNum;
	int repeatNum = pMyTest->repeatNum;
	pthread_mutex_lock(pMyTest->pMutIndex);
	rindex = pMyTest->repeatFlag[0];
	pMyTest->repeatFlag[0]++;
	pthread_mutex_unlock(pMyTest->pMutIndex);
	while(rindex < pMyTest->threadNum[0]*repeatNum-1) {
		pthread_mutex_lock(pMyTest->pMutIndex);
		index = pMyTest->index[0];
		pMyTest->index[0]++;
		pthread_mutex_unlock(pMyTest->pMutIndex);
		while(index < dataNum) {
			input = pMyTest->input[index];
			output = calculate(input);
			printf("index=%3u, input=%8u, output=%2u, threadID=%2u\n", index, input, output, threadID);
			pMyTest->output[index] = output;
			pthread_mutex_lock(pMyTest->pMutIndex);
			index = pMyTest->index[0];
			pMyTest->index[0]++;
			pthread_mutex_unlock(pMyTest->pMutIndex);
			
		}
		pthread_mutex_lock(pMyTest->pMutIndex);
		pMyTest->endFlag[0]++;
		pthread_mutex_unlock(pMyTest->pMutIndex);
		while(pMyTest->endFlag[0] < pMyTest->threadNum[0])
			;
		sleep(1);
		pMyTest->index[0] = 0;
		pMyTest->endFlag[0] = 0;
		sleep(1);
		pthread_mutex_lock(pMyTest->pMutIndex);
		index = pMyTest->index[0];
		pMyTest->input[index] = generate(index);
		pMyTest->index[0]++;
		pthread_mutex_unlock(pMyTest->pMutIndex);
		while(index < dataNum) {
			printf("threadid=%d,rindex=%d\n", threadID, rindex);
			pthread_mutex_lock(pMyTest->pMutIndex);
			pMyTest->input[index] = generate(index);
			pthread_mutex_unlock(pMyTest->pMutIndex);
			index = pMyTest->index[0];
			pMyTest->index[0]++;
		}
		pthread_mutex_lock(pMyTest->pMutIndex);
		pMyTest->endFlag[0]++;
		pthread_mutex_unlock(pMyTest->pMutIndex);
		printf("endflag%d\n", pMyTest->endFlag[0]);
		while(pMyTest->endFlag[0] < pMyTest->threadNum[0])
			;
		sleep(1);
		pMyTest->index[0] = 0;
		pMyTest->endFlag[0] = 0;
		pthread_mutex_lock(pMyTest->pMutIndex);
		rindex = pMyTest->repeatFlag[0];
		pMyTest->repeatFlag[0]++;
		pthread_mutex_unlock(pMyTest->pMutIndex);
		sleep(1);
		
	}
	pthread_mutex_lock(pMyTest->pMutIndex);
	pMyTest->threadNum[0]--;
	pthread_mutex_unlock(pMyTest->pMutIndex);
	pthread_exit(NULL);
}

int main(void) {
	int i, ret;
	int threadNum = 2;
	myTest * pMyTest = (myTest *)malloc(sizeof(myTest));
	pMyTest->dataNum = 10;
	pMyTest->repeatNum = 3;
	pMyTest->input = (int *)malloc(sizeof(int)*pMyTest->dataNum);
	pMyTest->output = (int *)malloc(sizeof(int)*pMyTest->dataNum);
	for(i=0; i<pMyTest->dataNum;++i) {
		pMyTest->input[i] = generate(i);
	}
	pMyTest->threadNum = (int *)calloc(1, sizeof(int));
	pMyTest->index = (int *)calloc(1, sizeof(int));
	pMyTest->endFlag = (int *)calloc(1, sizeof(int));
	pMyTest->repeatFlag = (int *)calloc(1, sizeof(int));

	pMyTest->pMutIndex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
	pthread_mutex_init(pMyTest->pMutIndex, NULL);

	pMyTest->threadNum[0] = threadNum;
	myTest * inMyTest = (myTest *)malloc(sizeof(myTest)*threadNum);
	for(i=0; i<threadNum; ++i) {
		memcpy(inMyTest+i, pMyTest, sizeof(myTest));
		(inMyTest+i)->threadID = i;
	}
	pthread_t * tid = (pthread_t*)malloc(sizeof(pthread_t)*threadNum);
	printf("Begin create pthread.\n");
	for(i=0; i<threadNum; ++i) {
		ret = pthread_create(tid+i, NULL, (void *)thread, (myTest *)(inMyTest+i));
		if(ret != 0) {
			printf("Create pthread error.\n");
			return 0;
		}
	}
	for(i=0; i<threadNum; i++)
		pthread_join(tid[i], NULL);
	free(tid);
	free(inMyTest);
	pthread_mutex_destroy(pMyTest->pMutIndex);
	free(pMyTest->pMutIndex);
	free(pMyTest->threadNum);
	free(pMyTest->input);
	free(pMyTest->output);
	free(pMyTest->index);
	free(pMyTest->endFlag);
	free(pMyTest->repeatFlag);
	free(pMyTest);
	return 0;
}


感觉这次的代码质量挺糟糕的。用了好多sleep和lock&unlock。其实老师布置的dataNum为10000,repeatNum为100的,但是那样的话得测试到什么时候..于是我缩减了好多倍......

删去了一些上个实验用到而这个实验用不到的东西。结构中主要添加的是repeatNum(类比dataNum)和repeatFlag(类比endFlag)。然后把threadNum从int型变成了int*型,因为要改变这个值,下面再具体说。

逻辑上把代码写好之后,在实际执行过程中遇到了问题(死循环、段错误什么的。。。)。

可以看到现在这个执行正确的代码中有这么几行(任务一和任务二中间):

sleep(1);
pMyTest->index[0] = 0;
pMyTest->endFlag[0] = 0;
sleep(1);

本打算在任务一中让index++,然后任务二中index--(endFlag同理),这样就不用对它进行赋值了。但是实际上不好完成。pMyTest->index[0] 在任务一完成后的值是12,感觉如果直接用这个数的话也没方便到哪儿去,所以还是选择了重新赋值。两个sleep是必须的。举个例子,假如没有第一行的sleep,线程0先执行完任务一然后把endFlag赋值为0,会把线程1卡在while中然后导致死循环,因为endFlag永远也不能等于threadNum了。

线程的最后还要执行这么一段代码:

pthread_mutex_lock(pMyTest->pMutIndex);
pMyTest->threadNum[0]--;
pthread_mutex_unlock(pMyTest->pMutIndex);

如果不加的话会出现什么情况呢?假如repeatNum为1,则任务一+任务二只执行一次,如果线程0已经开始执行任务一的话,线程1连最外层的while循环都进不去,如果直接执行pthread_exit的话,线程0又会在while那里死循环了。所以应该让程序知道线程1已经退出了。这也是把threadNum由int型更换为int*型的原因。

在重复执行任务一+任务二的时候,两个线程都会执行repeatflag++,这样会导致任务只能执行repeatNum的大约二分之一次。本想在repeatFlag++的时候判断,但是哪个线程先退出是一个未知数,所以我在while循环那里做了个手脚,最外层的while循环执行threadNum*repeatNum-1次,经测试能保证执行正确的次数。(不过数据量大的话不排除有出意外的可能)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值