本次实验要实现的是先判断input中的数是素数还是合数,然后对于input中的合数,寻找这个合数的最大约数(这个约数从input中的素数寻找)。然后把所找到的最大约数的行号以及合数的行号输出到一个数组中,要求这个数组的大小应该是input中合数的两倍。不过从我的执行结果来看,并不是所有的合数都能在input的素数中找到约数,也不知道我的结果对不对..还有一个要求,这两个具有先后顺序的功能必须在同一个线程中执行。所以在执行完任务一之后,线程们需要统一步伐然后再开始执行第二个任务。代码如下:
#include <stdio.h>
#include <pthread.h>
typedef struct myTestType
{
int threadID;
int threadNum;
int dataNum;
int *input;
int *output;
int *outrow;
int *index;
int *primeNum;
int *outRowSize;
int *endFlag;
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;
}
void thread(myTest * pMyTest) {
printf("Begin threadID=%u run!\n", pMyTest->threadID);
int index, input, output;
int threadID = pMyTest->threadID;
int dataNum = pMyTest->dataNum;
pthread_mutex_lock(pMyTest->pMutIndex);
index = pMyTest->index[0];
pMyTest->index[0]++;
pthread_mutex_unlock(pMyTest->pMutIndex);
int primeNum = 0;
int outRowSize = 0;
int rowIndex = 0;
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]++;
if(output == 0) {
primeNum++;
}
else {
outRowSize += 2;
}
pthread_mutex_unlock(pMyTest->pMutIndex);
}
pthread_mutex_lock(pMyTest->pMutIndex);
pMyTest->primeNum[0] += primeNum;
pMyTest->outRowSize[0] += outRowSize;
pMyTest->endFlag[0]++;
pthread_mutex_unlock(pMyTest->pMutIndex);
while(pMyTest->endFlag[0] < pMyTest->threadNum)
;
pMyTest->index[0] = 0;
sleep(1);
index = pMyTest->index[0];
pMyTest->index[0]++;
int i;
while(index < dataNum) {
int row = 0;
if(pMyTest->output[index] == 1) {
for(i=0; i<dataNum; i++) {
if(pMyTest->output[i] == 0 && pMyTest->input[index] % pMyTest->input[i] == 0) {
row = i;
}
}
}
pthread_mutex_lock(pMyTest->pMutIndex);
if(row != 0) {
pMyTest->outrow[rowIndex++] = row;
pMyTest->outrow[rowIndex++] = index;
printf("%d, %d\n", row, index);
}
index = pMyTest->index[0];
pMyTest->index[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 = 100;
pMyTest->input = (int *)malloc(sizeof(int)*pMyTest->dataNum);
pMyTest->output = (int *)malloc(sizeof(int)*pMyTest->dataNum);
pMyTest->outrow = (int *)malloc(sizeof(int)*pMyTest->dataNum);
for(i=0; i<pMyTest->dataNum;++i) {
if(i % 4 == 0)
pMyTest->input[i] = (1 << (i%30)) + 1;
else
pMyTest->input[i] = (7 << (i%16)) + 1;
}
pMyTest->index = (int *)calloc(1, sizeof(int));
pMyTest->primeNum = (int *)calloc(1, sizeof(int));
pMyTest->outRowSize = (int *)calloc(1, sizeof(int));
pMyTest->endFlag = (int *)calloc(1, sizeof(int));
pMyTest->pMutIndex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
pthread_mutex_init(pMyTest->pMutIndex, NULL);
pMyTest->threadNum = 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);
printf("素数个数:%d\n", pMyTest->primeNum[0]);
free(tid);
free(inMyTest);
pthread_mutex_destroy(pMyTest->pMutIndex);
free(pMyTest->pMutIndex);
free(pMyTest->input);
free(pMyTest->output);
free(pMyTest->outrow);
free(pMyTest->index);
free(pMyTest->primeNum);
free(pMyTest->outRowSize);
free(pMyTest->endFlag);
free(pMyTest);
return 0;
}
重点其实就在于怎么判断第一个任务是否已经执行完毕。如果是主线程判断的话,那么pthread_join就可以搞定。但是现在要求在线程中进行判定。所以在myTest结构中添加了一个参数endFlag,如果一个线程执行完任务一的话就把这个数加一。当endFlag的值等于threadNum,则说明任务一被所有线程执行完毕,可以继续执行第二个线程了,如果endFlag值小于threadNum,那么while循环会一直执行下去直到endFlag等于threadNum。
但是在执行第二个线程前,我需要把pMyTest->index[0]初始化为0。但是放在while循环上面的话,会导致任务一被重复执行。因为一个线程已经执行到了这一步但另一个线程还没。结果已经变成0的pMyTest->index[0]又赋给了index,这样的话后结束的线程会重新执行任务一。但是放在while循环下面的话又很难保证index[0]++之后其值会不会又被另一个线程赋为0。所以在赋值之后加了个sleep(1),然后就可以开始执行任务二了~
如果我没想错的话,任务二的时间复杂度应该是o(n2),有改进的空间。可以在任务一的时候就把素数存到一个数组中。进一步的话还可以排个序,这样的话合数就没有必要与大于自己的素数作比较了。不过这样会增加空间复杂度,也比较折腾......
结论:加强理论学习!