最近、私は仕事の数値解析を行ってきました。ほとんどの場合、比較的単純な概念に関する少量のデータです。今後のプロジェクトが登場するのを待って、より複雑なシステムを指数関数的に計算し始めました。私の実行時間は数十秒から数十分になりました。私は実行時間を短縮するために、pthreadを使ってコードを書く方法を学ぶことにしました。Pthreadループのセグメンテーションフォールト
このため、私は、シリアルメソッドとpthreadsを使用して行列を作成するプログラムに取り組んできました。私はこれらのn回のそれぞれを行い、各実行の平均時間を取るためにこのプログラムを書いています。このプログラムを単独のpthread_tを使って実行すると、意図したとおりに動作します。スレッドを追加すると、「セグメンテーションフォールト」エラーが発生します。
私のコードは次のとおりです。
fill.h
#ifndef FILL_H_
#define FILL_H_
#include <pthread.h>//Allows access to pthreads
#include <sys/time.h>//Allows the ability to pull the system time
#include <stdio.h>//Allows input and output
#include <stdlib.h>//Allows for several fundamental calls
#define NUM_THREADS 2
#define MAT_DIM 50
#define RUNS 1
pthread_t threads[NUM_THREADS];
pthread_mutex_t mutexmat;
typedef struct{
int id;
int column;
int* matrix[NUM_THREADS];
}WORKER;
#endif
fill.c
/*This routine will fill an array both in serial and parallel with random
*numbers. It will also display the real time it took to accomplish each task*/
/* C includes */
#include "fill.h"
/* Fills a matrix */
void fill(int start, int stop, int** matrix)
{
int i, j;
for(i = start; i < stop; i++)
{
for(j = 0; j < MAT_DIM; j++)
matrix[i][j] = rand() % 10;
}
}
void* work(void* threadarg)
{
/* Creates a pointer to a worker type variable*/
WORKER *this_worker;
/* Points this_worker at what thread arg is pointing to*/
this_worker = (WORKER*) threadarg;
/* Calculates my stopping point for this thread*/
int stop = this_worker-> column + (MAT_DIM/NUM_THREADS);
/* Used to drive matrix */
int i,j;
/* Fills portion of Matrix */
for(i = this_worker-> column; i < stop; i++)
{
/* Prints the column that matrix is working on */
printf("Worker %d working on column %d\n", this_worker->id, i);
for(j = 0; j < MAT_DIM; j++)
{
this_worker-> matrix[i][j] = rand() % 10;
}
}
/* Signals thread is done */
printf("Thread %d done.\n", this_worker-> id);
/* Terminates thread */
pthread_exit(NULL);
}
int main()
{
/* Seeding rand */
srand (time(NULL));
/* These will be used for loops */
int i, j, r, t;
/* Creating my matrices */
int* matrix_serial[MAT_DIM];
int* matrix_thread[MAT_DIM];
/* creating timeval variables */
struct timeval t0, t1;
/* Beginning serial solution */
/* Creating timer for serial solution */
gettimeofday(&t0, 0);
/* Creating serial matrix */
for(i = 0; i < MAT_DIM; i++)
matrix_serial[i] = (int*)malloc(MAT_DIM * sizeof(int));
/* Filling the matrix */
for(r = 0; r < RUNS; r++)
fill(0, MAT_DIM, matrix_serial);
/* Calculating how long it took to run */
gettimeofday(&t1, 0);
unsigned long long int delta_t = (t1.tv_sec * 1000000 + t1.tv_usec)
- (t0.tv_sec * 1000000 + t0.tv_usec);
double t_dbl = (double)delta_t/1000000.0;
double dt_avg = t_dbl/(double)r;
printf("\nSerial Run Time for %d runs: %f\t Average:%f\n",r, t_dbl, dt_avg);
/* Begin multithread solution */
/* Creating the offset where each matrix will start */
int offset = MAT_DIM/NUM_THREADS;
/* Creating a variable to store a return code */
int rc;
/* Creates a WORKER type variable named mat_work_t */
WORKER mat_work_t[NUM_THREADS];
/* Allocating a chunk of memory for my matrix */
for(i = 0; i < MAT_DIM; i++)
matrix_thread[i] = (int*)malloc(MAT_DIM * sizeof(int));
/* Begin main loop */
for(r = 0; r < RUNS; r++)
{
/* Begin multithread population of matrix */
for(t = 0; t < NUM_THREADS; t++)
{
/* Sets the values for mat_work_t[t] */
mat_work_t[t].id = t;
mat_work_t[t].column = t * offset;
/* Points the mat_work_t[t].matrix at the matrix_thread */
for(i = 0; i < MAT_DIM; i++)
mat_work_t[t].matrix[i] = &matrix_thread[i][0];
/* Creates thread placing its return value into rc */
rc = pthread_create(&threads[t],
NULL,
work,
(void*) &mat_work_t[t]);
/* Prints that a thread was successfully created */
printf("Thread %d created.\n", mat_work_t[t].id);
/* Checks to see if a return code was sent. If it was it will print it. */
if (rc)
{
printf("ERROR: return code from pthread_create() is %d\n", rc);
return(-1);
}
}
/* Makes sure all threads are done doing work before progressing */
printf("Waiting for workers to finish.\n");
for(i = 0; i < NUM_THREADS; i++)
pthread_join(threads[i], NULL);
printf("Work complete!\n");
}
/* Prints out the last matrix that was created by the loop */
for(i = 0; i < MAT_DIM; i++)
{
for(j = 0; j < MAT_DIM; j++)
printf("%d ",matrix_thread[i][j]);
printf("\n");
}
/* Terminates thread */
pthread_exit(NULL);
}
私は、GDBを実行すると、私が得る:セグメンテーションの
[New Thread 0x7ffff7fd3700 (LWP 27907)]
Thread 0 created.
Worker 0 working on column 0
Worker 0 working on column 1
Worker 0 working on column 2
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff7fd3700 (LWP 27907)]
0x0000000000400924 in work (threadarg=0x7fffffffd9c0) at fill.c:35
35 this_worker-> matrix[i][j] = rand() % 10;
私の理解を障害はかなりテキストであるOK:セグメンテーションフォルトは、アクセスする「あなた」以外のメモリにアクセスしようとすると発生します。このコードから、この行列が格納されているメモリにアクセスする際に問題が発生していることがわかります。
私の質問:
- は、右の問題の性質に私のロジックですか?
- なぜスレッドを追加するとこのプログラムが故障するのですか?
- 今後この種のトラブルシューティングを行うにはどうすればよいですか(ヒントがあれば幸いです)。
- 最後に、私はどのように修正するのですか(手がかりか解決策が大いに評価されます)?
ありがとうございます!私は今日、それを理解しようとしている間、頭に頭を打ちました。あなたは私に数え切れないほどの欲求不満の時間を救ってくれました。 –