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