仅使用一个线程时,程序运行无错误。但是,使用2个或更多线程时,根据运行情况,我会得到三个错误之一。分段错误,双重释放或损坏或释放():发生无效的指针。重要的main代码在thread_routine中。任何帮助表示赞赏。
在出现分段错误的情况下来自gdb的回溯:
#0 __memmove_sse2_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:525
#1 0x0000555555557153 in std::__copy_move<true, true, std::random_access_iterator_tag>::__copy_m<particle_t*> (__result=<optimized out>, __last=<optimized out>, __first=<optimized out>) at /usr/include/c++/7/bits/stl_algobase.h:368
#2 std::__copy_move_a<true, particle_t**, particle_t**> (__result=<optimized out>, __last=<optimized out>, __first=<optimized out>) at /usr/include/c++/7/bits/stl_algobase.h:386
#3 std::__copy_move_a2<true, particle_t**, particle_t**> (__result=<optimized out>, __last=0x55555577e910, __first=<optimized out>) at /usr/include/c++/7/bits/stl_algobase.h:424
#4 std::copy<std::move_iterator<particle_t**>, particle_t**> (__result=<optimized out>, __last=..., __first=...) at /usr/include/c++/7/bits/stl_algobase.h:456
#5 std::__uninitialized_copy<true>::__uninit_copy<std::move_iterator<particle_t**>, particle_t**> (__result=<optimized out>, __last=..., __first=...) at /usr/include/c++/7/bits/stl_uninitialized.h:101
#6 std::uninitialized_copy<std::move_iterator<particle_t**>, particle_t**> (__result=<optimized out>, __last=..., __first=...) at /usr/include/c++/7/bits/stl_uninitialized.h:134
#7 std::__uninitialized_copy_a<std::move_iterator<particle_t**>, particle_t**, particle_t*> (__result=<optimized out>, __last=..., __first=...) at /usr/include/c++/7/bits/stl_uninitialized.h:289
#8 std::__uninitialized_move_if_noexcept_a<particle_t**, particle_t**, std::allocator<particle_t*> > (__alloc=..., __result=<optimized out>, __last=0x55555577e910, __first=<optimized out>) at /usr/include/c++/7/bits/stl_uninitialized.h:312
#9 std::vector<particle_t*, std::allocator<particle_t*> >::_M_realloc_insert<particle_t* const&> (this=0x555555779088, __position=0x55555576b170, __args#0=@0x7ffff6e84e18: 0x555555776000) at /usr/include/c++/7/bits/vector.tcc:424
#10 0x00005555555569ca in std::vector<particle_t*, std::allocator<particle_t*> >::push_back (__x=@0x7ffff6e84e18: 0x555555776000, this=<optimized out>) at /usr/include/c++/7/bits/stl_vector.h:948
#11 Grid::addParticleToGrid (this=0x555555776a00, param=<optimized out>) at Grid.cpp:50
#12 0x00005555555559b1 in thread_routine (pthread_id=<optimized out>) at pthreads.cpp:67
#13 0x00007ffff7bbd6db in start_thread (arg=0x7ffff6e85700) at pthread_create.c:463
#14 0x00007ffff6fa788f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
free()无效指针的踪迹
#0 __memmove_sse2_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:486
#1 0x0000555555557153 in std::__copy_move<true, true, std::random_access_iterator_tag>::__copy_m<particle_t*> (__result=<optimized out>, __last=<optimized out>, __first=<optimized out>) at /usr/include/c++/7/bits/stl_algobase.h:368
#2 std::__copy_move_a<true, particle_t**, particle_t**> (__result=<optimized out>, __last=<optimized out>, __first=<optimized out>) at /usr/include/c++/7/bits/stl_algobase.h:386
#3 std::__copy_move_a2<true, particle_t**, particle_t**> (__result=<optimized out>, __last=0x55555577ec38, __first=<optimized out>) at /usr/include/c++/7/bits/stl_algobase.h:424
#4 std::copy<std::move_iterator<particle_t**>, particle_t**> (__result=<optimized out>, __last=..., __first=...) at /usr/include/c++/7/bits/stl_algobase.h:456
#5 std::__uninitialized_copy<true>::__uninit_copy<std::move_iterator<particle_t**>, particle_t**> (__result=<optimized out>, __last=..., __first=...) at /usr/include/c++/7/bits/stl_uninitialized.h:101
#6 std::uninitialized_copy<std::move_iterator<particle_t**>, particle_t**> (__result=<optimized out>, __last=..., __first=...) at /usr/include/c++/7/bits/stl_uninitialized.h:134
#7 std::__uninitialized_copy_a<std::move_iterator<particle_t**>, particle_t**, particle_t*> (__result=<optimized out>, __last=..., __first=...) at /usr/include/c++/7/bits/stl_uninitialized.h:289
#8 std::__uninitialized_move_if_noexcept_a<particle_t**, particle_t**, std::allocator<particle_t*> > (__alloc=..., __result=<optimized out>, __last=0x55555577ec38, __first=<optimized out>) at /usr/include/c++/7/bits/stl_uninitialized.h:312
#9 std::vector<particle_t*, std::allocator<particle_t*> >::_M_realloc_insert<particle_t* const&> (this=0x55555577bdd0, __position=0x0, __args#0=@0x7fffffffdb48: 0x55555576e320) at /usr/include/c++/7/bits/vector.tcc:424
#10 0x00005555555569ca in std::vector<particle_t*, std::allocator<particle_t*> >::push_back (__x=@0x7fffffffdb48: 0x55555576e320, this=<optimized out>) at /usr/include/c++/7/bits/stl_vector.h:948
#11 Grid::addParticleToGrid (this=0x555555776a00, param=<optimized out>) at Grid.cpp:50
#12 0x00005555555559b1 in thread_routine (pthread_id=<optimized out>) at pthreads.cpp:67
#13 0x0000555555555575 in main (argc=<optimized out>, argv=<optimized out>) at pthreads.cpp:137
双重释放或损坏()
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff6ec6801 in __GI_abort () at abort.c:79
#2 0x00007ffff6f0f897 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff703cb9a "%s\n") at ../sysdeps/posix/libc_fatal.c:181
#3 0x00007ffff6f1690a in malloc_printerr (str=str@entry=0x7ffff703e828 "double free or corruption (fasttop)") at malloc.c:5350
#4 0x00007ffff6f1e004 in _int_free (have_lock=0, p=0x55555577e360, av=0x7ffff7271c40 <main_arena>) at malloc.c:4230
#5 __GI___libc_free (mem=0x55555577e370) at malloc.c:3124
#6 0x000055555555718d in __gnu_cxx::new_allocator<particle_t*>::deallocate (this=<optimized out>, __p=<optimized out>) at /usr/include/c++/7/ext/new_allocator.h:125
#7 std::allocator_traits<std::allocator<particle_t*> >::deallocate (__a=..., __n=<optimized out>, __p=<optimized out>) at /usr/include/c++/7/bits/alloc_traits.h:462
#8 std::_Vector_base<particle_t*, std::allocator<particle_t*> >::_M_deallocate (this=<optimized out>, __n=<optimized out>, __p=<optimized out>) at /usr/include/c++/7/bits/stl_vector.h:180
#9 std::vector<particle_t*, std::allocator<particle_t*> >::_M_realloc_insert<particle_t* const&> (this=0x55555577a7e0, __position=0x4, __args#0=@0x7ffff6e84e18: 0x555555776480) at /usr/include/c++/7/bits/vector.tcc:448
#10 0x00005555555569ca in std::vector<particle_t*, std::allocator<particle_t*> >::push_back (__x=@0x7ffff6e84e18: 0x555555776480, this=<optimized out>) at /usr/include/c++/7/bits/stl_vector.h:948
#11 Grid::addParticleToGrid (this=0x555555776a00, param=<optimized out>) at Grid.cpp:50
#12 0x00005555555559b1 in thread_routine (pthread_id=<optimized out>) at pthreads.cpp:67
#13 0x00007ffff7bbd6db in start_thread (arg=0x7ffff6e85700) at pthread_create.c:463
#14 0x00007ffff6fa788f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
主要代码:
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <pthread.h>
#include "common.h"
#include "Grid.h"
std::unique_ptr<Grid, std::default_delete<Grid>> grid = nullptr;
//
// global variables
//
int n, n_threads, saveFreq;
particle_t *particles;
FILE *fsave;
pthread_barrier_t barrier;
//
// check that pthreads routine call was successful
//
#define P( condition ) {if( (condition) != 0 ) { printf( "\n FAILURE in %s, line %d\n", __FILE__, __LINE__ );exit( 1 );}}
//
// This is where the action happens
//
void *thread_routine( void *pthread_id )
{
int thread_id = *(int*)pthread_id;
int particles_per_thread = (n + n_threads - 1) / n_threads;
int first = min( thread_id * particles_per_thread, n );
int last = min( (thread_id+1) * particles_per_thread, n );
//
// simulate a number of time steps
//
for( int step = 0; step < NSTEPS; step++ )
{
//
// compute forces
//
for( int i = first; i < last; i++ )
{
particles[i].ax = particles[i].ay = 0;
std::unique_ptr<std::vector<particle_t *>> neighbours = grid->getNeighbouringParticles(particles[i]);
for (long j = 0; j < neighbours->size(); j++) {
particle_t *p = neighbours->at(j);
particle_t part = *p;
apply_force( particles[i], part);
}
}
pthread_barrier_wait( &barrier );
if (thread_id == 0) {
grid->clearGrid();
}
pthread_barrier_wait( &barrier );
//
// move particles
//
for( int i = first; i < last; i++ ) {
move( particles[i] );
grid->addParticleToGrid(&particles[i]);
}
pthread_barrier_wait( &barrier );
//
// save if necessary
//
if( thread_id == 0 && fsave && (step%saveFreq) == 0 )
save( fsave, n, particles );
}
return NULL;
}
//
// benchmarking program
//
int main( int argc, char **argv )
{
//
// process command line
//
if( find_option( argc, argv, "-h" ) >= 0 )
{
printf( "Options:\n" );
printf( "-h to see this help\n" );
printf( "-n <int> to set the number of particles\n" );
printf( "-p <int> to set the number of threads\n" );
printf( "-o <filename> to specify the output file name\n" );
printf( "-f <int> to specify the savefreq\n" );
return 0;
}
n = read_int( argc, argv, "-n", 1000 );
n_threads = read_int( argc, argv, "-p", 1 );
char *savename = read_string( argc, argv, "-o", NULL );
saveFreq = read_int( argc, argv, "-f", SAVEFREQ );
//
// allocate resources
//
fsave = savename ? fopen( savename, "w" ) : NULL;
particles = (particle_t*) malloc( n * sizeof(particle_t) );
set_size( n );
init_particles( n, particles );
grid = std::unique_ptr<Grid>(new Grid(n, size));
grid->addParticlesToGrid(particles, n);
pthread_attr_t attr;
P( pthread_attr_init( &attr ) );
P( pthread_barrier_init( &barrier, NULL, n_threads ) );
int *thread_ids = (int *) malloc( n_threads * sizeof( int ) );
for( int i = 0; i < n_threads; i++ )
thread_ids[i] = i;
pthread_t *threads = (pthread_t *) malloc( n_threads * sizeof( pthread_t ) );
//
// do the parallel work
//
double simulation_time = read_timer( );
for( int i = 1; i < n_threads; i++ )
P( pthread_create( &threads[i], &attr, thread_routine, &thread_ids[i] ) );
thread_routine( &thread_ids[0] );
for( int i = 1; i < n_threads; i++ )
P( pthread_join( threads[i], NULL ) );
simulation_time = read_timer( ) - simulation_time;
printf( "n = %d, n_threads = %d, simulation time = %g seconds\n", n, n_threads, simulation_time );
//
// release resources
//
P( pthread_barrier_destroy( &barrier ) );
P( pthread_attr_destroy( &attr ) );
free( thread_ids );
free( threads );
free( particles );
if( fsave )
fclose( fsave );
return 0;
}
我的网格类
//
// Created by sharf on 2019-02-26.
//
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <bits/unique_ptr.h>
#include "Grid.h"
Grid::Grid(int len, double width) :
gridWidth(width)
{
numColumns = (long) ceil(sqrt(len));
numRows = (long) ceil(len / (double)numColumns);
columnWidth = width/((double)numColumns - 1);
numBoxes = numRows * numColumns;
boxes = std::unique_ptr<std::vector<particle_t *>[]>(new std::vector<particle_t *>[numBoxes]);
}
Grid::~Grid()
{
}
long Grid::getSqrIdFromCoord(double x, double y)
{
long iX = (long) floor(x/getColWidth());
long iY = (long) floor(y/getColWidth());
return iX + iY*getNumColumns();
}
long Grid::getNumBoxes() const { return numBoxes; }
double Grid::getGridWidth() const { return gridWidth; }
long Grid::getNumColumns() const { return numColumns; }
long Grid::getNumRows() const { return numRows; }
double Grid::getColWidth() const { return columnWidth; }
void Grid::clearGrid() {
for (long i = 0; i < numBoxes; i++) {
boxes[i].clear();
}
}
void Grid::addParticleToGrid(particle_t *param) {
long index = getSqrIdFromCoord(param->x, param->y);
boxes[index].push_back(param);
}
void Grid::addParticlesToGrid(particle_t *particles, int numParticles)
{
for (long i = 0; i < numParticles; i++)
{
long index = getSqrIdFromCoord(particles[i].x, particles[i].y);
boxes[index].push_back(&particles[i]);
}
}
std::unique_ptr<std::vector<particle_t *>> Grid::getNeighbouringParticles(particle_t param) {
long particleIndex = getSqrIdFromCoord(param.x, param.y);
std::vector<particle_t *> particles;
// Get right neighbour if possible
if ((particleIndex % numColumns) < (numColumns - 1)) {
for (int i = 0; i < boxes[particleIndex+1].size(); i++) {
particles.push_back(boxes[particleIndex+1][i]);
}
}
// Get left neighbour if possible
if ((particleIndex % numColumns) > 0) {
for (int i = 0; i < boxes[particleIndex-1].size(); i++)
particles.push_back(boxes[particleIndex-1][i]);
}
// Get top neighbour if possible
long rowIndex = ((long) floor(particleIndex / numColumns));
if (rowIndex < (numRows - 1)) {
for (int i = 0; i < boxes[particleIndex + numColumns].size(); i++)
particles.push_back(boxes[particleIndex + numColumns][i]);
}
// Get bot neighbour if possible
if (rowIndex > 0) {
for (int i = 0; i < boxes[particleIndex - numColumns].size(); i++)
particles.push_back(boxes[particleIndex - numColumns][i]);
}
// Get top right neighbour if possible
if (rowIndex < (numRows - 1) && (particleIndex % numColumns) < (numColumns - 1)) {
for (int i = 0; i < boxes[particleIndex + numColumns + 1].size(); i++)
particles.push_back(boxes[particleIndex + numColumns + 1][i]);
}
// Get top left neighbour if possible
if ((particleIndex % numColumns) > 0 && rowIndex < (numRows - 1)) {
for (int i = 0; i < boxes[particleIndex + numColumns - 1].size(); i++)
particles.push_back(boxes[particleIndex + numColumns - 1][i]);
}
// Get bot right neighbour if possible
if (rowIndex > 0 && (particleIndex % numColumns) < (numColumns - 1)) {
for (int i = 0; i < boxes[particleIndex - numColumns + 1].size(); i++) {
particles.push_back(boxes[particleIndex - numColumns + 1][i]);
}
}
// Get bot left neighbour if possible
if (rowIndex > 0 && (particleIndex % numColumns) > 0) {
for (int i = 0; i < boxes[particleIndex - numColumns - 1].size(); i++)
particles.push_back(boxes[particleIndex - numColumns - 1][i]);
}
return std::unique_ptr<std::vector<particle_t *>> (new std::vector<particle_t *>(particles));
}
Grid.h
#ifndef PROJECT_GRID_H
#define PROJECT_GRID_H
#include <vector>
#include "common.h"
#include <bits/unique_ptr.h>
class Grid {
std::unique_ptr<std::vector<particle_t *>[]> boxes;
long numBoxes, numColumns, numRows;
double gridWidth, columnWidth;
long getSqrIdFromCoord(double x, double y);
public:
Grid(int len, double width);
~Grid();
long getNumBoxes() const;
long getNumRows() const;
long getNumColumns() const;
double getGridWidth() const;
double getColWidth() const;
void clearGrid();
void addParticlesToGrid(particle_t *particles, int numParticles);
std::unique_ptr<std::vector<particle_t *>> getNeighbouringParticles(particle_t param);
void addParticleToGrid(particle_t *param);
};
#endif //PROJECT_GRID_H
Common.h
#ifndef __CS267_COMMON_H__
#define __CS267_COMMON_H__
extern double size;
inline int min( int a, int b ) { return a < b ? a : b; }
inline int max( int a, int b ) { return a > b ? a : b; }
//
// saving parameters
//
const int NSTEPS = 1000;
const int SAVEFREQ = 10;
//
// particle data structure
//
typedef struct
{
double x;
double y;
double vx;
double vy;
double ax;
double ay;
} particle_t;
//
// timing routines
//
double read_timer( );
double findMedian(double *arr, int len);
//
// simulation routines
//
void set_size( int n );
void init_particles( int n, particle_t *p );
void apply_force( particle_t &particle, particle_t &neighbor );
void move( particle_t &p );
//
// I/O routines
//
FILE *open_save( char *filename, int n );
void save( FILE *f, int n, particle_t *p );
//
// argument processing routines
//
int find_option( int argc, char **argv, const char *option );
int read_int( int argc, char **argv, const char *option, int default_value );
char *read_string( int argc, char **argv, const char *option, char *default_value );
#endif
Common.cpp
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <float.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include "common.h"
double size;
//
// tuned constants
//
#define density 0.0005
#define mass 0.01
#define cutoff 0.01
#define min_r (cutoff/100)
#define dt 0.0005
//
// timer
//
double read_timer( )
{
static bool initialized = false;
static struct timeval start;
struct timeval end;
if( !initialized )
{
gettimeofday( &start, NULL );
initialized = true;
}
gettimeofday( &end, NULL );
return (end.tv_sec - start.tv_sec) + 1.0e-6 * (end.tv_usec - start.tv_usec);
}
// compares two doubles and returns if theyre equal
int comp(const void * x, const void * y)
{
double f = *((double *)x);
double s = *((double *)y);
if (f > s) return 1;
if (f < s) return -1;
return 0;
}
// Finds a media from a sorted array.
double findMedian(double *arr, int len) {
qsort(arr, len, sizeof(double), comp);
if (len % 2 != 0)
return arr[len/2];
return (arr[len/2] + arr[(len/2) - 1])/2;
}
//
// keep density constant
//
void set_size( int n )
{
size = sqrt( density * n );
}
//
// Initialize the particle positions and velocities
//
void init_particles( int n, particle_t *p )
{
srand48( time( NULL ) );
int sx = (int)ceil(sqrt((double)n));
int sy = (n+sx-1)/sx;
int *shuffle = (int*)malloc( n * sizeof(int) );
for( int i = 0; i < n; i++ )
shuffle[i] = i;
for( int i = 0; i < n; i++ )
{
//
// make sure particles are not spatially sorted
//
int j = lrand48()%(n-i);
int k = shuffle[j];
shuffle[j] = shuffle[n-i-1];
//
// distribute particles evenly to ensure proper spacing
//
p[i].x = size*(1.+(k%sx))/(1+sx);
p[i].y = size*(1.+(k/sx))/(1+sy);
//
// assign random velocities within a bound
//
p[i].vx = drand48()*2-1;
p[i].vy = drand48()*2-1;
}
free( shuffle );
}
//
// interact two particles
//
void apply_force( particle_t &particle, particle_t &neighbor )
{
double dx = neighbor.x - particle.x;
double dy = neighbor.y - particle.y;
double r2 = dx * dx + dy * dy;
if( r2 > cutoff*cutoff )
return;
r2 = fmax( r2, min_r*min_r );
double r = sqrt( r2 );
//
// very simple short-range repulsive force
//
double coef = ( 1 - cutoff / r ) / r2 / mass;
particle.ax += coef * dx;
particle.ay += coef * dy;
}
//
// integrate the ODE
//
void move( particle_t &p )
{
//
// slightly simplified Velocity Verlet integration
// conserves energy better than explicit Euler method
//
p.vx += p.ax * dt;
p.vy += p.ay * dt;
p.x += p.vx * dt;
p.y += p.vy * dt;
//
// bounce from walls
//
while( p.x < 0 || p.x > size )
{
p.x = p.x < 0 ? -p.x : 2*size-p.x;
p.vx = -p.vx;
}
while( p.y < 0 || p.y > size )
{
p.y = p.y < 0 ? -p.y : 2*size-p.y;
p.vy = -p.vy;
}
}
//
// I/O routines
//
void save( FILE *f, int n, particle_t *p )
{
static bool first = true;
if( first )
{
fprintf( f, "%d %g\n", n, size );
first = false;
}
for( int i = 0; i < n; i++ )
fprintf( f, "%g %g\n", p[i].x, p[i].y );
}
//
// command line option processing
//
int find_option( int argc, char **argv, const char *option )
{
for( int i = 1; i < argc; i++ )
if( strcmp( argv[i], option ) == 0 )
return i;
return -1;
}
int read_int( int argc, char **argv, const char *option, int default_value )
{
int iplace = find_option( argc, argv, option );
if( iplace >= 0 && iplace < argc-1 )
return atoi( argv[iplace+1] );
return default_value;
}
char *read_string( int argc, char **argv, const char *option, char *default_value )
{
int iplace = find_option( argc, argv, option );
if( iplace >= 0 && iplace < argc-1 )
return argv[iplace+1];
return default_value;
}
答案 0 :(得分:1)
查看所有三个堆栈跟踪,它们共有的共同区域是Grid::addParticleToGrid
,特别是boxes[index].push_back(param);
行(在向量世界中迷失了)。由于boxes[index]
是std::vector<particle_t *>
,并且向量不是线程安全的,因此您在多个线程中获得相同的index
值,导致多个线程试图同时修改向量
由于这是一个家庭作业问题,因此我将其保留为“读者练习”,以解决该问题。