实验三:Linux 多线程编程

任务 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<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<unistd.h>
#include<pthread.h>
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 <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>
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 <niters>\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<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>
#include<stdbool.h>
#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;
}

需要手动Ctrl+c结束进程,不然消费者进程会一直等待唤醒,而此时生产者进程已经结束不可能唤醒消费者进程。
在这里插入图片描述

任务 4:编译、测试和运行示例程序 psum64.c 1)测量线程数为 1、2、4、8、16 时程序的执行时间,计算加速比和效率,并做出解释。 2)改写该程序 psum64.c,保存为 task34.c,实现计算 02+12+… +(n-1)2 功能。

tsak34.c

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#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 <nthreads> <log_nelems>\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⁵个数字的加法

要求:计算不同线程数时的性能,填写以下表格,并对运行时间和加速比进行解释:
关于加速比和效率可参考文章 加速比
单处理器下的时间即只运行一个线程所用的时间

原创文章 8 获赞 2 访问量 1908

猜你喜欢

转载自blog.csdn.net/myszpl/article/details/105947805