任务 1:编写程序 task31.c,主线程创建 3 个对等线程 T1、T2、T3,每个线程利用循环执行 5 次
printf 输出操作,两次循环间随机等待 1-5s 时间。主线程等待所有对等线程结束后终止进程。各对等
线程的输出操作是:
T1:输出“My name is <您的姓名 xxx>”
T2:输出“My student number is <您的学号 xxx>”
T3:输出“Current time <当前时间,包括年月日时分秒>
task31.c
#include
#include
#include
#include
#include
void* thread_name(){
for(int i=0;i<5;i++){
printf("My name is \n");
int time = rand()%5+1;
sleep(time);
}
}
void* thread_num(){
for(int i=0;i<5;i++){
printf("My student number is\n");
int time = rand()%5+1;
sleep(time);
}
}
void* thread_time(){
time_t now;
for(int i=0;i<5;i++){
struct tm *tm_now;
time(&now);
tm_now = localtime(&now);
printf("Current time is: %d-%d-%d %d:%d:%d\n",
tm_now->tm_year+1900, tm_now->tm_mon+1, tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);
int time = rand()%5+1;
sleep(time);
}
}
int main(){
pthread_t t1,t2,t3;
pthread_create(&t1,NULL,thread_name,NULL);
pthread_create(&t2,NULL,thread_num,NULL);
pthread_create(&t3,NULL,thread_time,NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
}
gcc task31.c -o task31 -pthread
./task31
任务 2:
编译、测试和运行图 6-13 示例程序 badcount.c,请通过测试找到程序运行开始出错的 niters 的最小值,并解释出错原因。用 pthread 信号量方法改写程序 badcount.c,保存为 task62.c,实现对共享变量的安全访问,并进行测试验证。
task32.c
#include
#include
#include
#include
void *increase(void *arg);
void *decrease(void *arg);
unsigned int cnt = 0;
pthread_mutex_t mutex;
int main(int argc, char **argv)
{
unsigned int niters;
pthread_t tid1, tid2;
if(argc!=2) {
printf("usage:%s \n" ,argv[0]);
exit(2);
}
pthread_mutex_init(&mutex,NULL);
niters=atoll(argv[1]);
pthread_create(&tid1, NULL, increase, (void*)&niters);
pthread_create(&tid2, NULL, decrease, (void*)&niters);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
if (cnt != (unsigned int)0)
printf("Error! cnt=%d\n", cnt);
else
printf("Correct cnt=%d\n", cnt);
exit(0);
}
void *increase(void *vargp)
{
unsigned int i,niters=*(unsigned int* )vargp;
for (i = 0; i < niters; i++){
pthread_mutex_lock(&mutex);
cnt++;
pthread_mutex_unlock(&mutex);
}
return NULL;
}
void *decrease(void *vargp)
{
unsigned int i,niters=*(unsigned int *)vargp;
for (i = 0; i < niters; i++){
pthread_mutex_lock(&mutex);
cnt--;
pthread_mutex_unlock(&mutex);
}
return NULL;
}
用 niters=10n 进行测试,给出 badcount.c 开始出错的 n 最小值,解释出错原因;
n=5时开始出错,赋值语句是由多条汇编语句组成的,当数量过多时可能出现错误
任务 3:编写一个多线程程序 task33.c,创建 k 个生产者线程和 m 个消费者线程,每个生产者线程 产生若干个随机数,通过由 N 个单元构成的缓冲区,发送给消费者线程,进行输出显示,产生 pthread 信号量实现生产者/消费者线程间同步,并且设计一种方案对程序正确性进行验证。
提示:一种非严谨的简单验证方案是,将生产者线程产生的所有随机数相加得到一个和,消费者
线程接收到的所有随机数相加得到另一个和,验证两个和是否一致来来验证程序正确性。
task33.c
#include
#include
#include
#include
#include
#define N 20
#define K 10
#define M 20
int buf[N];
//sum_out记录生产者生产总数,sum_in记录消费者接收总数
int outpos = 0,inpos = 0,sum_out=0,sum_in=0;
sem_t avail,ready;
pthread_mutex_t out,in;
void sbuf_insert(int item){
buf[inpos]=item;
inpos=(inpos+1)%N;
}
int sbuf_remove(){
int item=buf[outpos];
outpos=(outpos+1)%N;
return item;
}
void *Thread_P(){
bool flag=true;
while(flag){
int i = rand()%100;
sem_wait(&avail);
pthread_mutex_lock(&in);
sbuf_insert(i);
sum_out+=i;
if(sum_out >= 666666){//生产总数达到一定数值后结束线程
flag=false;
printf("we product %d\n",sum_out);
}
pthread_mutex_unlock(&in);
sem_post(&ready);
}
}
void *Thread_C(){
while(1){
sem_wait(&ready);
pthread_mutex_lock(&out);
int i = sbuf_remove();
sum_in+=i;
printf("we receive %d\n",sum_in);
pthread_mutex_unlock(&out);
sem_post(&avail);
}
}
int main(){
sem_init(&avail,0,N);
sem_init(&ready,0,0);
pthread_mutex_init(&out,NULL);
pthread_mutex_init(&in,NULL);
pthread_t pro[K];//生产者
pthread_t cus[M];//消费者
for(int i=0;i<K;i++){
pthread_create(&pro[i],NULL,Thread_P,NULL);
}
for(int i=0;i<M;i++){
pthread_create(&cus[i],NULL,Thread_C,NULL);
}
for(int i=0;i<K;i++){
pthread_join(pro[i],NULL);
}
for(int i=0;i<M;i++){
pthread_join(cus[i],NULL);
}
return 0;
}
任务 4:编译、测试和运行示例程序 psum64.c 1)测量线程数为 1、2、4、8、16 时程序的执行时间,计算加速比和效率,并做出解释。 2)改写该程序 psum64.c,保存为 task34.c,实现计算 02+12+… +(n-1)2 功能。
tsak34.c
#include
#include
#include
#define MAXTHREADS 32
void *sum(void *vargp);
/* Global shared var��ables */
unsigned long long psum[MAXTHREADS]; /* Partial sum computed by each thread */
unsigned long long nelems_per_thread; /* Number of elements summed by each thread */
int main(int argc , char **argv)
{
unsigned long long i , nelems , log_nelems , nthreads , result = 0;
pthread_t tid[MAXTHREADS];
int myid[MAXTHREADS];
/*Get input arguments */
if (argc != 3) {
printf ("Usage: %s \n" , argv [0]) ;
exit(0);
}
nthreads = atoi(argv[1]) ;
log_nelems = atoi(argv[2]);
nelems = (1L << log_nelems);
nelems_per_thread = nelems / nthreads;
/* Create peer threads and wait for them to f��nish */
for (i = 0; i < nthreads; i++) {
myid [i] = i;
pthread_create (&tid[i],NULL, sum, &myid[i]);
}
for (i = 0; i < nthreads; i++)
pthread_join(tid[i] ,NULL) ;
/* Add Up the partial sums computed by each thread */
for (i = 0; i < nthreads; i++)
result += psum[i];
/* Check final answer */
if (result == (nelems*(nelems-1)*(2*nelems-1)/6))
printf("Correct Result=%lld\n",result);
else
printf("Error: result=%lld\n" , result);
exit(0);
}
void *sum(void* argp)
{
int myid = *((int*)argp); /* Extract the thread ID */
unsigned long long start = myid *nelems_per_thread; /* Start element index */
unsigned long long end = start + nelems_per_thread; /* F.nd element index */
unsigned long long i, lsum= 0;
for (i = start; i < end; i++) {
lsum += i*i;
}
psum[myid] = lsum;
return NULL;
}
nthreads = atoi(argv[1]) ;//获取第一个参数作为线程总数
log_nelems = atoi(argv[2]);//第二个参数作为2的指数幂
nelems = (1L << log_nelems);//加到2的 log_nelems次方为止
nelems_per_thread = nelems / nthreads;//分配每个线程执行多少
例如当传进参数2 和10:
从0加到2¹⁰-1,分给两个线程执行,每个线程执行2⁵个数字的加法
要求:计算不同线程数时的性能,填写以下表格,并对运行时间和加速比进行解释:
关于加速比和效率可参考文章 加速比
单处理器下的时间即只运行一个线程所用的时间