/* Compilation: gcc -o exam1 exam1.c -lpthread */ // Параллельное умножение квадратной матрицы А размерностью NxN // на вектор B, результат - вектор C. // Создается nt потоков, каждый из которых умножает ленту матрицы // A размерностью (N/nt)xN на вектор B. // Умножение повторяется nc раз при неизменной матрице A и // различных векторах B. #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <signal.h> #define _REENTRANT #include <pthread.h> #include <sched.h> typedef struct { pthread_t tid; int first; int last; pthread_mutex_t mutx; pthread_cond_t condx; } ThreadRecord; int N; // Размер матрицы A и векторов B, C double *A, *B, *C; int done=0; ThreadRecord *threads; // Массив мьютексов и условн. переменных void * mysolver (void *arg_p) { ThreadRecord *thr; int i, j; thr = (ThreadRecord *)arg_p; pthread_mutex_lock( &(thr->mutx) ); while ( 1 ) { fprintf (stderr, "\t%d\n", thr->tid); for (i=thr->first; i<=thr->last; i++) { C[i] = 0; for (j=0; j<=N; j++) C[i] += A[N*i+j]*B[j]; }; pthread_cond_wait(&(thr->condx), &(thr->mutx)); }; } int main (int argc, char* argv[]) { int nt; // Кол-во расчетных потоков int nc; // Кол-во циклов int i, j, k; pthread_attr_t pattr; if (argc != 4) { fprintf(stderr, "Исп: %s размерность #потоков #циклов\n", argv[0]); exit (1); }; N = atoi(argv[1]); nt = atoi(argv[2]); nc = atoi(argv[3]); if ( N%nt ) { fprintf(stderr, "Размерность д.б. кратна кол-ву потоков\n", argv[0]); exit (2); }; // Выделение памяти A = (double *) malloc( sizeof(double)*N*N ); B = (double *) malloc( sizeof(double)*N ); C = (double *) malloc( sizeof(double)*N ); // Инициализация A и B случ. значениями srand(time(NULL)); for (i=0; i<N; i++) { B[i] = (double) rand(); for (j=0; j<N; j++) A[i*N+j] = (double) rand(); }; pthread_attr_init (&pattr); pthread_attr_setscope (&pattr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setdetachstate (&pattr,PTHREAD_CREATE_JOINABLE); threads = (ThreadRecord *) calloc (nt, sizeof(ThreadRecord)); j = N/nt; for (i=0; i<nt; i++) { threads[i].first = j*i; // Индекс нач. строки А для потока threads[i].last = j*(i+1)-1; // Индекс конечн. строки А для потока pthread_mutex_init (&(threads[i].mutx), NULL); pthread_cond_init (&(threads[i].condx), NULL); if ( pthread_create (&(threads[i].tid), &pattr, mysolver, (void *) &(threads[i])) ) perror("pthread_create"); sched_yield(); // Попытка стартовать поток как можно быстрее }; for (k=1; k<nc; k++) { usleep(100000); // Попытка дать шанс расчетному потоку // вернуть себе мьютекс - весьма критичная величина!!!!!!!!!!!!!!!! fprintf(stderr, "---------\n"); for (i=0; i<nt; i++) { pthread_mutex_lock( &(threads[i].mutx) ); }; for (j=0; j<N; j++) B[j] = (double) rand(); for (i=0; i<nt; i++) { pthread_mutex_unlock( &(threads[i].mutx) ); pthread_cond_signal( &(threads[i].condx) ); sched_yield(); }; }; exit (0); }