實驗三: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⁵個數字的加法

要求:計算不同線程數時的性能,填寫以下表格,並對運行時間和加速比進行解釋:
關於加速比和效率可參考文章 加速比
單處理器下的時間即只運行一個線程所用的時間

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章