作业帮助,分段错误,双重释放或损坏,free():无效的指针

时间:2019-03-16 23:55:39

标签: c++ multithreading pthreads

仅使用一个线程时,程序运行无错误。但是,使用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;
}

1 个答案:

答案 0 :(得分:1)

查看所有三个堆栈跟踪,它们共有的共同区域是Grid::addParticleToGrid,特别是boxes[index].push_back(param);行(在向量世界中迷失了)。由于boxes[index]std::vector<particle_t *>,并且向量不是线程安全的,因此您在多个线程中获得相同的index值,导致多个线程试图同时修改向量

由于这是一个家庭作业问题,因此我将其保留为“读者练习”,以解决该问题。