代码描述
NOTES:
一共有3个线程:main thread、producer、consumer
main thread:读取command line paramters 运送到与生产者共享的buffer1
producer thread:从buffer1中取数据,进行加工factorNumber,再运送至与消费者共享的buffer2
consumer thread:从buffer2中取数据(消费),并展示加工的结果。
说明
buffer1为一维数组,buffer2为二维指针数组
代码还需在内存申请方面进行优化,不过我严格了限制条件,producer与consumer只会本分的工作,consumer消费完所有参数就会退出,以防内存泄漏。
优化思路:buffer的动态内存申请、race condition的优化、buffer考虑用结构体等。
代码性能
buffer1与buffer2标准size为50,经过调优可以将buffer1的size设置为2,buffer2的size设置为2,线程可处理2000个命令行参数(因为define 了 argc的最大值),即使将argcMAX调大也可正常运行,BINGGO!
Makefile文件
#MakeFile
CC=gcc
CFLAGS=-Wall -g -MMD -MP
INCLUDES=-I ./include
ALLOC_LINK=-ldl -lrt -lpthread
main: main.o producer.o consumer.o prodcons.o
$(CC) $(INCLUDES) $(CFLAGS) -o $@ $^ $(ALLOC LINK)
-mkdir -p bin
mv $@ bin -f
main.o:main.c
$(CC) -C $(INCLUDES) $(CFLAGS) main.c
producer.o: producer.c
$(CC) -C $(INCLUDES) $(CFLAGS) producer.c
consumer.o:consumer.c
$(CC) -C $(INCLUDES) $(CFLAGS) consumer.c
prodcons.o:prodcons.c
$(CC) -C $(INCLUDES) $(CFLAGS) prodcons.c
clean:
rm -f main.0 producer.o consumer.o prodcons.o
rm -f main.d producer.d consumer.d prodcons.d
rm -f bin/main
代码:
//main.c
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include"prodcons.h"
#include"consumer.h"
#include"producer.h"
#include"string.h"
#define _GNU_SOURCE
//#pragma comment(lib, "pthreadVC2.lib")
void* mainthread(void* data)
{
//main thread
int num = 0;
int *input = data;
while (1)
{
//race condition
while (counter == BUFFER_SIZE1)
;//do nothing
pthread_mutex_lock(&mutex1);
if (num < argvcounter)
{
buffer[in] = input[num];
in = (in + 1) % BUFFER_SIZE1;
counter++;
num++;
}
pthread_mutex_unlock(&mutex1);
}
}
int main(int argc, char* argv[]) {
//no command line
if (argc == 1)
{
fprintf(stderr,"usage: ./assn4 <number to factor>...\n");
return -1;
}
else {
for (int i = 1; i < argc; ++i)
{
if (atoi(argv[i]) < 0)
{
fprintf(stderr, "command line paramters must be >= 0\n");
return -1;
}
}
}
//handle command line parameters
int *inputParam = (int*)malloc(sizeof(int));
if (argc == 2 && *argv[1] == '{')
{
char* p = argv[1];
char* ptr = NULL;
char* re = NULL;
int begin = 0, end = 0;
if (argc == 2 && *argv[1] == '{')
{
p++;
begin = atoi(p);
re = strtok_s(p, "..", &ptr);
re = strtok_s(NULL, "..", &ptr);
end = atoi(re);
}
int j = 0;
for (int i = begin; i <= end; ++i)
{
inputParam = realloc(inputParam, (j + 1) * sizeof(int));
inputParam[j] = i;
j++;
}
argvcounter = (end - begin)+1;
}
else
{
int x = 0;
for (int i = 1; i < argc; ++i)
{
inputParam = realloc(inputParam, (x + 1) * sizeof(int));
inputParam[x] = atoi(argv[i]);
++x;
}
argvcounter = argc - 1;
}
pthread_t child1;
pthread_t child2;
pthread_t child3;
counter = 0;
in = 0;
out = 0;
bp_out = 0, bp_in = 0, bp_count = 0;
int ini1 = pthread_mutex_init(&mutex1, NULL);
int ini2 = pthread_mutex_init(&mutex2, NULL);
if (ini1 != 0 || ini2 != 0)
{
printf("mutex init failed \n");
exit(1);
}
pthread_create(&child1, NULL, mainthread, inputParam);
pthread_create(&child2, NULL, producer, NULL);
pthread_create(&child3, NULL, consumer, NULL);
//destroy all threads and free BUffer
pthread_join(child1, NULL);
pthread_join(child2, NULL);
pthread_join(child3, NULL);
free(inputParam);
free(BufferPool);
return 0;
}
//producer.c
#include<stdio.h>
#include<stdlib.h>
#include"producer.h"
//facror number
void factor2pc(int* p, int number)
{
int i, j = 1;
p[0] = number;
if (number == 0 ||number == 1)
{
//p = realloc(p, 2*sizeof(int));
p[1] = number;
return NULL;
}
for (i = 2; i <= number; i++) {
while (number % i == 0) {
//p = realloc(p, (j + 1) * sizeof(int));
p[j] = i;
++j;
number /= i;
}
}
return NULL;
}
void* producer(void* data)
{
while (1)
{
int temp = -1;
//buffer which save each factor number
int *Tempbuffer = (int*)malloc(sizeof(int) * ARGVMAX);
//race condition
while (counter == 0);
pthread_mutex_lock(&mutex1);//with the main thread
//critical area
temp = buffer[out];
out = (out + 1) % BUFFER_SIZE1;
counter--;
pthread_mutex_unlock(&mutex1);
//factor number
factor2pc(Tempbuffer, temp);
//race condition
while (bp_count == BUFFER_SIZE2);
pthread_mutex_lock(&mutex2);//with the consumer thread
//critical area
BufferPool[bp_in] = Tempbuffer;
bp_in = (bp_in + 1) % BUFFER_SIZE2;
bp_count++;
pthread_mutex_unlock(&mutex2);
//free(Tempbuffer);
}
}
//consumer.c
#include<stdio.h>
#include<stdlib.h>
#include"consumer.h"
void* consumer(void* data) {
int limit = 0;
while (1)
{
int i = 0, Numberlimit;
if (limit >= argvcounter)
{
exit(-1);
}
//race condition
while (bp_count == 0);
pthread_mutex_lock(&mutex2);
//make sure the output format is correct
if (bp_out < argvcounter)
{
printf("%d:",(*BufferPool[bp_out])[0]);
i++;
Numberlimit = (*BufferPool[bp_out])[0];
while (i < ARGVMAX)
{
//limit condition
if ((*BufferPool[bp_out])[i] < 0 || (*BufferPool[bp_out])[i] > Numberlimit) break;
printf("%d ", (*BufferPool[bp_out])[i]);
++i;
}
++limit;
printf("\n");
bp_out = (bp_out + 1) % BUFFER_SIZE2;
bp_count--;
}
pthread_mutex_unlock(&mutex2);
}
}
//producer.h
#ifndef PRODUCER
#define PRODUCER
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include"prodcons.h"
#define BUFFER_SIZE1 (20)//smaller buffer size
#define MAX 100
//the buffer jointly owned by producer and the main thread
int buffer[BUFFER_SIZE1];
int in, out;
int counter;
int argvcounter;
pthread_mutex_t mutex1;
void factor2pc(int *p, int number);
void* producer(void* data);
#endif
//prodcons.h
#pragma once
#ifndef PRODCONS
#define PRODCONS
#include<pthread.h>
#define BUFFER_SIZE2 (2)// when finished, can try size 2 for fun
#define ARGVMAX 2000
//the BufferPool jointly owned by producer and consumer
int (*BufferPool[BUFFER_SIZE2])[ARGVMAX];
int bp_in, bp_out, bp_count;
pthread_mutex_t mutex2;
#endif
//consumer.h
#pragma once
#ifndef CONSUMER
#define CONSUMER
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include"prodcons.h"
#include"producer.h"
void* consumer(void* data);
#endif
控制台输出: