Gnuplot调用应用程序时崩溃

4

我想在控制台应用程序(C ++,Eclipse CDT,Linux)中使用gnuplot绘制我的结果。 我创建了一个简单的类来使事情更容易(请参见下面的代码)。 我尝试在我的主函数中绘制一个测试图:

int main() {

    Gnuplot plot;

    plot("plot sin(x)") ;

    cout<<"Press button:";
    cin.get();

    return 0;
}

我的问题是,如果我正常启动应用程序,执行线条plot("plot sin(x)")后,我会收到一个运行时错误消息,“无法初始化wxWidgets。分段错误(core dumped)”。但是,如果我在调试模式下逐行执行代码,则代码可以正常工作,并且我的绘图窗口按预期显示正弦波。欢迎任何帮助。

#ifndef GNUPLOT_H_
#define GNUPLOT_H_

#include <string>
using namespace std;

class Gnuplot {

    public:
        Gnuplot() ;
        ~Gnuplot();
        void operator ()(const string & command); // send any command to gnuplot

    protected:
        FILE *gnuplotpipe;
};
#endif

以及源代码:

#include "gnuplot.h"
#include <iostream>
#include <string>
#include "stdio.h"

Gnuplot::Gnuplot() {

    gnuplotpipe=popen("gnuplot -persist","w");
    if (!gnuplotpipe) {
    cerr<< ("Gnuplot not found !");
    }
}

Gnuplot::~Gnuplot() {

    fprintf(gnuplotpipe,"exit\n");
    pclose(gnuplotpipe);
}

void Gnuplot::operator()(const string & command) {

    fprintf(gnuplotpipe,"%s\n",command.c_str());
    fflush(gnuplotpipe);// flush is neccessary, nothing gets plotted else
};

你没有展示任何与WxWidget相关的代码。如果你使用了widget代码,请展示出来。同时使用g++ -Wall -g进行编译,并学会使用gdb调试器。 - Basile Starynkevitch
它运行良好,在窗口中绘制了预期的正弦曲线。Sleep(1)没有帮助(我包含了unistd.h来编译)。 - JustGreg
也许在 popen 后面加上 sleep(1) 会有所帮助... 显然,gnuplot 正在使用 WxWidgets,并且对您来说正在崩溃... - Basile Starynkevitch
在绘图命令之前尝试添加“set terminal png; set output 'graph.png';”,这样可以将图形发送到文件而不是屏幕上。这样可以吗? - Paul
你确定有一个 DISPLAY 吗? - Basile Starynkevitch
显示剩余5条评论
2个回答

2

没有与X服务器的链接执行会导致此问题。通常情况下,ssh不会给您提供与X服务器的链接(但可以进行配置或切换以这样做)。我发现,如果我尝试通过"ssh localhost"进入gnuplot并输入绘图命令,它将默认为wxt是终端类型,并给出"failed to initiaize wxWidgets"错误和段错误。

但是,我发现如果我先执行以下操作,则可以解决该问题。

警告:第一个命令"xhost +"很危险,它会禁用X安全性并允许来自互联网上任何地方的任何东西连接到您的屏幕、键盘或鼠标。如果机器在网络地址转换路由器后面(例如家庭网络中使用的路由器),则可能问题较小。

从shell中执行:

xhost +
export DISPLAY=:0.0

以编程方式启动gnuplot,然后按照正常的方法发送gnuplot命令。
应该可以工作。在我目前的ssh登录中工作。如果不行,请检查使用的环境来启动新进程,并明确地放置“DISPLAY=:0.0”。这意味着连接到本地显示器。也可以在之前加上主机名:

在Linux下,gnuplot通常会寻找X服务器。它可能找不到它。

也许如果目标是将图形保存在文件中,则添加:

set terminal png
set output 'graph.png'

在“plot”命令之前添加gnuplot命令。即使在无头服务器上,这也应该有效。

如果您想控制输出文件名,请发送其他名称而不是graph.png。


这很好,但我需要某种交互性(缩放)来验证我的计算和算法。因此,我会坚持使用窗口图。然而,知道在我的显示方面出了问题也是好的。 - JustGreg
在终端中输入xhost +和export DISPLAY=:0.0,然后通过在IDE中运行它来启动我的应用程序,不幸的是出现了相同的错误消息。 - JustGreg
在Linux和大多数Unix系统中,env是一个共享的值字符串(更或者说是一个基于字符串的关联数组),它会被传递给进程树。你需要将DISPLAY=:0.0放入到env中。popen()并不能实现这个功能。你可能需要使用execve;http://linux.die.net/man/2/execve - Paul
如果您通过ssh执行X操作,使用ssh -X比向任何人开放访问您的X服务器更安全。 - liori
一个好的 IDE 可能会有一种检查环境的方式。你可以使用 'system "set"' 在 gnuplot 中进行检查。这只是在 shell 中运行 "set" 命令,它会打印环境变量。但是即使如此,这也可能会误导人,因为我们不知道有多少环境变量是从 gnuplot 传递给它所生成的 shell 的,因为可以更改子进程继承其环境变量的方式。 - Paul
显示剩余8条评论

1
下面这段代码(使用C语言,而非C++)对我来说正常运行(当在某个X11会话内的终端启动时,因此DISPLAY设置为:0.0):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char**argv)
{
  FILE *gp = NULL;
  if (!getenv("DISPLAY")) 
    {fprintf(stderr, "no display\n"); exit(EXIT_FAILURE);};
  gp = popen("gnuplot -persist", "w");
  if (!gp) {perror("gnuplot popen"); exit(EXIT_FAILURE);};
  //sleep (1);
  fprintf(gp, "plot sin(x)\n");
  fflush(gp);
  fprintf(gp, "exit\n");
  fflush(gp);
  //sleep (1);
  pclose (gp);
  return 0;
}     

(在Debian/Sid x86-64上使用gnuplot 4.6补丁级别0进行操作)

我猜sleep可以实际上有用,让gnuplot有足够的时间来工作。并且不要忘记在每个命令后面使用fflush

添加说明:

你应该有一个DISPLAY。如果出现“no display”错误消息,则意味着您在错误的环境中启动了程序。在这种情况下,没有编程技巧能帮助,因为gnuplot需要一些X11服务器来交流。

所以你应该更详细地解释如何启动你的程序。我猜这仅仅因为Eclipse运行时使用了一些X11服务器,而没有Eclipse时您恰好没有任何可用的X11服务器。(我不能解释原因,因为它非常依赖于您启动程序的方式。如果使用ssh,不要忘记使用ssh -X并适当地配置ssh)。

事实上,我的对sleep的调用是无用的。但测试DISPLAY的存在是必要的。 实际上这是gnuplot中的一些错误,应该在没有DISPLAY的情况下更好地失败;我在他们的错误跟踪器上添加了一个票。您可以使用unset DISPLAY; echo 'plot sin(x); exit' | gnuplot -persist重现此错误。

如果省略sleep/flush,是否会重复wxWidget的错误信息? - Paul
@Basile:感谢您花时间编写代码。它的工作方式与我的相同:逐步执行很好,正常运行会崩溃并出现相同的错误。 - JustGreg
@Basile:它存在但没有显示。 - JustGreg
@Paul:使用sudo apt-get update,但并没有太多变化。我需要重新启动系统吗?(抱歉,我只使用Linux三个月) - JustGreg
@JustGreg 通常重启后会有帮助,但并非总是必要的。有时候会出现一些问题,比如新内核中的某些内容不兼容。 - Paul
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接