3

我有一个工作程序来分析 C++ 中的数据,迄今为止已经产生了大约 35 个成功的数据文件。我在 Code:Blocks 中的 Scientific Linux 上工作时,它工作并排除了一些涉及非常大的网格尺寸(1000x1000+)的小错误,它完美地工作并产生了我正在寻找的东西。

我最近切换到 Ubuntu 并希望它能正常工作,但事实并非如此。它接受初始输入(第一个粒子开关),但随后立即崩溃并出现分段错误 139。我试图在 Windows 中运行它而不是使用我的双启动,但它似乎无法识别本地文件系统,所以我被迫寻求帮助。

这是一个很长的程序,所以我将重现整个过程。我提前道歉。

// This program converts the column output of a 1D PIC code into a workable solution

#include <iostream>
#include <fstream>
#include <math.h>
using namespace std;

double calculateXMaximum(double arraymax[], int size)
{
    double maximum = 0;
    for (int k = 1; k < size/2; k++)
    {
        if(arraymax[2*k] > maximum)
        {
            maximum = arraymax[2*k];
        }
    }
    return maximum;
}

double calculateXMinimum(double arraymin[], int size)
{
    double minimum = 0;
    for (int k = 1; k < size/2; k++)
    {
        if(arraymin[2*k] < minimum)
        {
            minimum = arraymin[2*k];
        }
    }
    return minimum;
}

double calculatePXMaximum(double arraymax[], int size)
{
    double maximum = 0;
    for (int k = 1; k < size/2; k++)
    {
        if(arraymax[2*k+1] > maximum)
        {
            maximum = arraymax[2*k+1];
        }
    }
    return maximum;
}

double calculatePXMinimum(double arraymin[], int size)
{
    double minimum = 0;
    for (int k = 1; k < size/2; k++)
    {
        if(arraymin[2*k+1] < minimum)
        {
            minimum = arraymin[2*k+1];
        }
    }
    return minimum;
}

int main()
{
// Variables settable before running program - will set up initialisation later.
double xmin = 0;
double xmax = 0;
double pmin = 0;
double pmax = 0;

int xni = 0;
double xntemp = 0;
double deltax = 0;
int xi; // X interpolates, defined from console for resolution of diagram

int pnj = 0;
double pntemp = 0;
double deltap = 0;
int pi;
int type;
double modifier;

// Determines momentum modifier!

cout << "For particle type, enter 1 (e-) or 2 (p+)" << endl;
cout << "Particle type:  ";
cin >> type;

if (type == 2)
{
    modifier = 1836;
}
else
{
    modifier = 1;
}

ifstream inputFile;
ofstream outputFile;

inputFile.open ("/home/Nick/fi020000.dat");
outputFile.open ("/home/Nick/fi20k.dat");

int dataformat[2];
for(int rd = 0; rd < 2; rd++)
{
    dataformat[rd] = 0;
    inputFile >> dataformat[rd];
}

int records = dataformat[1] + 2;
double data[records];
cout << "Number of particles: " << dataformat[1]/2 << endl;


// Introduction of data from input data file loop.  Produces records.
for (int count = 0; count < records; count++)
{
    inputFile >> data[count];
}

// Calling functions for xmin and xmax.  May streamline later

xmax = calculateXMaximum(data, records) * 1.1;
cout << "Maximum x value: " << xmax << endl;
xmin = calculateXMinimum(data, records) * 1.1;
cout << "Minimum x value: " << xmin << endl;
pmax = calculatePXMaximum(data, records) * 1.1 / modifier;
cout << "Maximum p value: " << pmax << endl;
pmin = calculatePXMinimum(data, records) * 1.1 / modifier;
cout << "Minimum p value: " << pmin << endl;

// Definition of bin size

cout << "Entire desired number of x bins: ";
cin >> xi;
const int xip = xi;
cout << "Enter desired number of p bins: ";
cin >> pi;
const int pip = pi;
cout << "Grid is " << xip << " x " << pip << endl;

// Calculate DELTA X and DELTA P
deltax = (xmax - xmin)/(xip);
deltap = (pmax - pmin)/(pip);

cout << "Resolution of x:  " << deltax << endl;
cout << "Resolution of p:  " << deltap << endl;

int phaseSpace [xip][pip];
for(int i=0; i<xip; i++)
{
    for(int j=0; j<pip; j++)
    {
        phaseSpace[i][j] = 0;
    }
}

for (int phasecount=1; phasecount < (records/2)-1; phasecount++)
{
    xntemp = (data[2*phasecount] - xmin)/deltax;
    xni = floor(xntemp);
    pntemp = ((data[(2*phasecount)+1] / modifier) - pmin)/deltap;
    pnj = floor(pntemp);
    phaseSpace[xni][pnj] = phaseSpace[xni][pnj] + 1;
}

for (int xoutcount = 0; xoutcount < xip; xoutcount++)
{
    for (int poutcount = 0; poutcount < pip; poutcount++)
    {
        outputFile << xmin+((xoutcount+0.5)*deltax) << " " << pmin+((poutcount+0.5)*deltap) << " "<< phaseSpace[xoutcount][poutcount] << endl;
    }
    outputFile << endl;
}


cout << "Program complete" << endl;

return 0;

}

我的目标是在本周末之前完成一份 30 页的报告,但现在我用来执行此操作的程序已经完全崩溃了。我不是计算机科学家——我是物理学家,不到一个月前我学会了 C++。因此,我不知道发生了什么。我知道这个话题已经看过很多,但我不能真正理解这些建议。

编辑:堆栈跟踪是:

#0 0x4010af     ??     ()     (??:??)
#1 0x7ffff7215ea5       __libc_start_main() (/lib/x86_64-linux-gnu/libc.so.6:??)
#2 0x4017f1 ??    () (??:??)

EDIT2:Valgrind 结果

==4089== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==4089== Command: ./Analysis
==4089== 
For particle type, enter 1 (e-) or 2 (p+)
Particle type:  2
==4089== Warning: client switching stacks?  SP change: 0x7fefff9c0 --> 0x7fe6d7118
==4089==          to suppress, use: --max-stackframe=9603240 or greater
==4089== Invalid write of size 8
==4089==    at 0x4010AF: ??? (in /home/paladin/Contour/Analysis/bin/Release/Analysis)
==4089==    by 0x5673EA4: (below main) (libc-start.c:260)
==4089==  Address 0x7fe6d7118 is on thread 1's stack
==4089== 
==4089== 
==4089== Process terminating with default action of signal 11 (SIGSEGV)
==4089==  Access not within mapped region at address 0x7FE6D7118
==4089==    at 0x4010AF: ??? (in /home/paladin/Contour/Analysis/bin/Release/Analysis)
==4089==  If you believe this happened as a result of a stack
==4089==  overflow in your program's main thread (unlikely but
==4089==  possible), you can try to increase the size of the
==4089==  main thread stack using the --main-stacksize= flag.
==4089==  The main thread stack size used in this run was 8388608.
==4089== 
==4089== Process terminating with default action of signal 11 (SIGSEGV)
==4089==  Access not within mapped region at address 0x7FE6D7111
==4089==    at 0x4A256A0: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-amd64-linux.so)
==4089==  If you believe this happened as a result of a stack
==4089==  overflow in your program's main thread (unlikely but
==4089==  possible), you can try to increase the size of the
==4089==  main thread stack using the --main-stacksize= flag.
==4089==  The main thread stack size used in this run was 8388608.
==4089== 
==4089== HEAP SUMMARY:
==4089==     in use at exit: 17,520 bytes in 4 blocks
==4089==   total heap usage: 4 allocs, 0 frees, 17,520 bytes allocated
==4089== 
==4089== LEAK SUMMARY:
==4089==    definitely lost: 0 bytes in 0 blocks
==4089==    indirectly lost: 0 bytes in 0 blocks
==4089==      possibly lost: 0 bytes in 0 blocks
==4089==    still reachable: 17,520 bytes in 4 blocks
==4089==         suppressed: 0 bytes in 0 blocks
==4089== Rerun with --leak-check=full to see details of leaked memory
==4089== 
==4089== For counts of detected and suppressed errors, rerun with: -v
==4089== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)
Segmentation fault (core dumped)

故障发生在 ifstream inputFile 语句中。

EDIT3:根据要求,控制台会话:

paladin@paladin:~/Programming/Contour Constructor 2/bin/Debug$ ./Contour\ Constructor\ 2 
For particle type, enter 1 (e-) or 2 (p+)
Particle type:  2
Segmentation fault (core dumped)

输入文件有1200402行,对应PIC代码中的600200个粒子加上2个描述行。

EDIT4: 在这里在黑暗中完成拍摄,但我最初是在 Scientific Linux 上的 GCC 4.4.7 下编译的。我现在使用的是最新的 Ubuntu 版本(4.8.1)。在此期间是否发生了一些变化,这会使我正在使用的文件的大小无效?

4

4 回答 4

6

这里的重要提示是 valgrind 认为你正在切换线程——当然从你展示的代码来看,你没有使用多个线程。由于多线程程序中的每个线程都有自己的堆栈,因此 valgrind 假定如果堆栈指针的变化超过某个阈值(请参阅 valgrind 输出中提到的 --max-stackframe),您将切换到不同的线程。

实际上,发生的事情是您创建了一个巨大的堆栈帧,准确地说是 9603240 字节。这超过了您可能默认获得的 8MB 左右。您可以通过查看 shell 来查看当前的软限制:

$ ulimit -s
8192

换句话说,堆栈被限制为 8MB。如果您超过该限制,Linux 将假定发生了一些错误(tm)并终止您的进程。

您可以立即使用的一种解决方法是提高限制,或者将其设置为无限制:

$ ulimit -s 16384 # 16MB stack
$ ulimit -s unlimited # "unlimited" stack

这应该可以阻止您的进程崩溃,并解释为什么它在一个盒子上运行良好而不是另一个盒子(它工作的那个可能默认设置了更高的堆栈大小限制)。

现在,从设计的角度来看,创建这么大的堆栈帧通常是个坏主意。对于大型分配,您应该使用堆内存,例如:

double data[records];

可以替换为

double *data = new double[records];

// use data ...

delete[] data;

而是从堆中分配和释放内存。这将使您首先避免此类问题。或者,您始终可以使用标准容器之一,例如 std::vector<>` 来避免该问题。

于 2013-09-12T17:43:57.893 回答
2

如果您仅在大输入大小时看到此问题,则在创建时可能会出现堆栈溢出phaseSpace,因为这可能是一个非常大的数组。如果您使用 astd::vector而不是普通数组,则应避免此类问题:

#include <vector>

// ...

// A vector containing vectors containing integers.
// Initialized to contain the appropriate amount of space filled with zeros
std::vector< std::vector<int> > phaseSpace(pip, std::vector<int>(xip, 0));

您的其余代码可能与向量相同。


或者,如果xnipni超出范围,您将覆盖随机内存。您可以添加输出语句来显示这些值并查看是否有问题。

于 2013-09-12T16:32:18.057 回答
0

我很惊讶这个程序甚至可以编译:您声明的数组大小在编译时无法确定,如下所示。你能告诉你正在使用哪个编译器吗?

int records = dataformat[1] + 2;
double data[records];
于 2013-09-12T16:30:55.980 回答
0

这就是使用 std::vector 而不是原生数组的样子。

// This program converts the column output of a 1D PIC code into a
// workable solution

#include <cmath>
#include <fstream>
#include <iostream>
#include <limits>
#include <vector>

double calculateXMaximum(const std::vector<double>& arraymax) {
  double maximum = -std::numeric_limits<double>::max();
  for (unsigned k = 1; k < arraymax.size()/2; ++k) {
    maximum = std::max(arraymax[2*k], maximum);
  }
  return maximum;
}

double calculateXMinimum(const std::vector<double>& arraymin) {
  double minimum = std::numeric_limits<double>::max();
  for (unsigned k = 1; k < arraymin.size()/2; ++k) {
    minimum = std::min(arraymin[2*k], minimum);
  }
  return minimum;
}

double calculatePXMaximum(const std::vector<double>& arraymax) {
  double maximum = -std::numeric_limits<double>::max();
  for (unsigned k = 1; k < arraymax.size()/2; ++k) {
    maximum = std::max(arraymax[2*k+1], maximum);
  }
  return maximum;
}

double calculatePXMinimum(const std::vector<double>& arraymin) {
  double minimum = std::numeric_limits<double>::max();
  for (unsigned k = 1; k < arraymin.size()/2; ++k) {
    minimum = std::min(arraymin[2*k+1], minimum);
  }
  return minimum;
}

int main()
{
  // Variables settable before running program
  //  - will set up initialisation later.

  int xni = 0;
  double xntemp = 0;
  int xi; // X interpolates, defined from console for resolution of diagram

  int pnj = 0;
  double pntemp = 0;
  int pi;
  int type;

  // Determines momentum modifier!

  std::cout << "For particle type, enter 1 (e-) or 2 (p+)\n";
  std::cout << "Particle type:  ";
  std::cin >> type;

  const double modifier = (type == 2) ? 1836.0 : 1.0;

  std::ifstream inputFile("fi020000.dat");
  std::ofstream outputFile("fi20k.dat");

  int dataformat[2];
  inputFile >> dataformat[0];
  inputFile >> dataformat[1];

  int records = dataformat[1] + 2;
  std::vector<double> data(records, 0.0);
  std::cout << "Number of particles: " << dataformat[1]/2 << std::endl;


  // Introduction of data from input data file loop.  Produces records.
  for (int count = 0; count < records; ++count) {
    inputFile >> data[count];
  }

  // Calling functions for xmin and xmax.  May streamline later

  const double xmax = calculateXMaximum(data) * 1.1;
  std::cout << "Maximum x value: " << xmax << std::endl;
  const double xmin = calculateXMinimum(data) * 1.1;
  std::cout << "Minimum x value: " << xmin << std::endl;
  const double pmax = calculatePXMaximum(data) * 1.1 / modifier;
  std::cout << "Maximum p value: " << pmax << std::endl;
  const double pmin = calculatePXMinimum(data) * 1.1 / modifier;
  std::cout << "Minimum p value: " << pmin << std::endl;

  // Definition of bin size

  std::cout << "Entire desired number of x bins: ";
  std::cin >> xi;
  const int xip = xi;
  std::cout << "Enter desired number of p bins: ";
  std::cin >> pi;
  const int pip = pi;
  std::cout << "Grid is " << xip << " x " << pip << std::endl;

  // Calculate DELTA X and DELTA P
  const double deltax = (xmax - xmin)/(xip);
  const double deltap = (pmax - pmin)/(pip);

  std::cout << "Resolution of x:  " << deltax << std::endl;
  std::cout << "Resolution of p:  " << deltap << std::endl;

  std::vector< std::vector<int> > phaseSpace(xip, std::vector<int>(pip, 0));

  for (int phasecount=1; phasecount < (records/2)-1; ++phasecount) {
    xntemp = (data[2*phasecount] - xmin)/deltax;
    xni = std::floor(xntemp);
    pntemp = ((data[(2*phasecount)+1] / modifier) - pmin)/deltap;
    pnj = std::floor(pntemp);
    phaseSpace[xni][pnj] = phaseSpace[xni][pnj] + 1;
  }

  for (int xoutcount = 0; xoutcount < xip; ++xoutcount) {
    for (int poutcount = 0; poutcount < pip; ++poutcount) {
      outputFile << xmin+((xoutcount+0.5)*deltax) << " " << pmin+((poutcount+0.5)*deltap) << " " << phaseSpace[xoutcount][poutcount] << "\n";
    }
    outputFile << "\n";
  }

  std::cout << "Program complete" << std::endl;

  return 0;
}

我删除了一些std::endl调用并将它们替换为"\n"以避免不必要的 I/O 缓冲区刷新。

我对最小值和最大值的计算方式做了一些改动。

我移动了一些变量声明,并const在可能的情况下制作它们。

重要提示:您应该在ifstream阅读输入时检查您的状态。就目前而言,您可以阅读文件末尾并且永远不知道它。似乎对data数组的内容也存在误解。似乎您认为它包含您的两个主要描述行。但是,您已经将这两个数字从流中提取到 中dataformat,因此您不需要考虑它们。

一组非常小的手动验证测试输入和输出数据将很有用。

于 2013-09-12T19:06:59.973 回答