如何在不拖延C中的父进程的情况下派生子进程



我的GTK+2/C应用程序使用Opencv库从网络摄像机馈送中连续抓取帧,并且有一个UI按钮,它应该通过点击时抓取帧来计算一些信息。

此按钮点击计算需要1-2秒,具体取决于系统资源。(在Raspberry pi上,需要3-5秒)

以前,所有功能(查看+计算)都在同一个主流程中。然而,在进行计算时,整个应用程序(视频馈送)习惯于冻结,直到计算完成。

我已经实现了fork()来制作子进程,并通过pipe()保持进程间通信,以使用计算的数据更新UI。

然而,现在滞后时间变得更大了,比如5-6秒。下面显示了示例代码。

有什么特别的方法可以避免这种主要过程的滞后吗?

#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
#include <diamond_calcs.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/videodev.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <opencv/cv.h>
#include <opencv/cxcore.h>
#include "highgui.h"
#include <X11/Xlib.h>

/* declaring the opencv capture variable */
CvCapture* capture, *fm_capture;
GdkPixbuf* pix;
IplImage* frame, *frame_sized;
gboolean expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data);
gboolean timeout(gpointer data);
gboolean autoon_clicked_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data[]);

// This function grabs a frame and recording some values. also this is the function called by the child process also.
gboolean frame_grabber(void)
{
    /* setting up the edge ditection */
    IplImage *frame_bgr;
    if(frame){
        //frame_bgr = cvQueryFrame( capture );
        frame_bgr = frame_sized;
    }
    else{
        frame_bgr = cvLoadImage("./data/media/novideo.png", 1);
    }
    /* Converting Color SPACE to greyscale */
    int y_pos, x_pos;
    int counter=0;
    typedef enum { false, true } bool;
    bool col_break = false;
    for(int y=0;y<frame_bgr->height;y++)
    {
        for(int x=0;x<frame_bgr->width;x++)
        {
            CvScalar color = cvGet2D(frame_bgr, y, x);
            if(color.val[0]<color_filter_thres){
                if (y_pos == y){
                    counter++;   
                }
                x_pos = x;
                y_pos = y;
                if (counter > 2){
                    //printf("top: %i, %i n", x_pos, y_pos);
                    col_break = true;
                    break;
                }
            }
        }
        if (col_break){
            break;
        }
    }
    ruler_top_cal_preset = y_pos;    
    /* bottom ruler - scanning backwards*/  
    int y_pos_bot, x_pos_bot;
    int counter_bot=0;
    bool col_break2 = false;
    for(int y_b=frame_bgr->height-1;y_b>0;y_b--)
    {
        for(int x_b=frame_bgr->width-1;x_b>0;x_b--)
        {
            CvScalar color_bot = cvGet2D(frame_bgr, y_b, x_b);
            if(color_bot.val[0]<color_filter_thres){
                if (y_pos_bot == y_b){
                    counter_bot++;   
                }
                x_pos_bot = x_b;
                y_pos_bot = y_b;
                if (counter_bot > 2){
                    //printf("bottom: %i, %i n", x_pos_bot, y_pos_bot);
                    col_break2 = true;
                    break;
                }
            }
        }
        if (col_break2){
            break;
        }
    }

    ruler_bottom_cal_preset = y_pos_bot;
    dfactor_preset = ruler_bottom_cal_preset - ruler_top_cal_preset;
}
/*
 * main
 *
 * Program begins here
 */
//####### Lot of processes going inside main, ignore it, just focus on the program flow
int main( int argc, char **argv )
{
    /* variables structs to load the gtk_ based widgets and windows */
    GtkBuilder *builder;
    GtkWidget  *window, *event_box, *drawing_area;
    GError     *error = NULL;
    GError     *error_settings = NULL;
    GtkButton *button;
    GtkLabel *label;
    /* Init GTK+ */
    gtk_init( &argc, &argv );
    /* Create new GtkBuilder object */
    builder = gtk_builder_new();
    /* Load UI from file. If error occurs, report it and quit application. */
    if( ! gtk_builder_add_from_file( builder, "file_glade.glade", &error ) )
    {
        g_warning( "%s", error->message );
        g_free( error );
        return( 1 );
    }
    /* Get main window pointer from UI */
    window = GTK_WIDGET( gtk_builder_get_object( builder, "window1" ) );

    /* creating the drawing area */
    drawing_area = gtk_drawing_area_new();
    gtk_container_add (GTK_CONTAINER(event_box), drawing_area);
    gtk_widget_show (drawing_area);
    /* connects the draw (expose-event) with the handler */   
    g_signal_connect (drawing_area, "expose-event",
    G_CALLBACK (expose_event_callback), NULL);

    gtk_label_set(labels[0], "Min   :");
    //####### Here goes the calculation clicking
    gtk_signal_connect (GTK_OBJECT (gtk_builder_get_object( builder, "autoon_button" )), "clicked",
                        GTK_SIGNAL_FUNC (autoon_clicked_cb), labels);
    /* Show window. All other widgets are automatically shown by GtkBuilder */
    gtk_widget_show( window );
    /* load last saved values */
    file_load( spinners );
    //#######
    int fd; 
    if((fd = open("/dev/video0", O_RDONLY)) == -1){   
        printf("NO CAPn");
        capture = NULL;
    }
    else{
        capture = cvCreateCameraCapture(0);
        cvSetCaptureProperty(capture, CV_CAP_PROP_BRIGHTNESS, brght);
        cvSetCaptureProperty(capture, CV_CAP_PROP_CONTRAST,contra);
        cvSetCaptureProperty(capture, CV_CAP_PROP_SATURATION, satu);
        cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 800);
        cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 600);
       // ## remove the forking from here and add that to the expose function 
        pid_t pID1 = vfork();
        if (pID1 == 0)                // child process
        {
          g_timeout_add (15, timeout, drawing_area);  
          //_exit(0);
        }
        else if ( pID1 < 0 ){
          printf("Failed to fork video overlay child process n");
          exit(1);
        }
    }
    /* Destroy builder, since we don't need it anymore */
     g_object_unref( G_OBJECT( builder ) );
    //g_object_unref( G_OBJECT( settings_builder ) );
    //g_object_unref( G_OBJECT( about_builder ) );
    /* Start main loop */
    gtk_main();

    return( 0 );
}
/* This function runs every x seconds and making the video feed */
/*
 * Function:  expose_event_callback
 * --------------------
 * When the widget is exposed of force to expose ths function handler will run to generate the video feed
 *  
 *  returns: none
 */
gboolean
expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
    /* Capture a single frame from the video stream */
    if (capture){
        frame = cvQueryFrame( capture );
        frame_sized = frame; 
        pix = gdk_pixbuf_new_from_data((guchar*) frame->imageData,
               GDK_COLORSPACE_RGB, FALSE, frame->depth, frame->width,
               frame->height, (frame->widthStep), NULL, NULL);
    }
    else{
        printf("You've done itn");
        pix = gdk_pixbuf_new_from_file("./data/media/novideo.png", NULL);
    }
    /* putting the generated pix buff to the correct layout (GTK widget) */    
    gdk_draw_pixbuf(widget->window,
     widget->style->fg_gc[GTK_WIDGET_STATE (widget)], pix, 0, 0, 0, 0,
     -1, -1, GDK_RGB_DITHER_NONE, 0, 0); /* Other possible values are  GDK_RGB_DITHER_MAX,  GDK_RGB_DITHER_NORMAL */
    return TRUE;
}
/*
 * Function:  timeout
 * --------------------
 * This function runs inbetween given time period. It calls the required functions to generate video and drawing
 *  
 *  returns: none
 */
gboolean timeout(gpointer data)
{
    /* DEBUG print */
    //printf("Time out Hello: %dn", rand());
    /* Redraws the Widget. Widget will call for the callback function again */
    gtk_widget_queue_draw (data);
    /* Starting the drawing function */
    //ofdra(data,NULL);
    return TRUE;
}
gboolean autoon_clicked_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data[])
{   
  char display1_entry_text[100];
  int x = 1;
    int pfds[2];
    pipe(pfds);
    pid_t pID = fork();
    if (pID == 0)                // child process
    {
      double ytops[10];
      double ybots[10];    
      double min_diam;
      double max_diam;
      double avg_diam;
      clock_t t1, t2,end_t; // clocking for debugging purposes
      t2 = clock();
      for(int i=0;i<15;i++)
      {
        //measure_clicked_callback(widget, NULL, data);
        frame_grabber();
        ytops[i] = ruler_top_cal_preset;
        ybots[i] = ruler_bottom_cal_preset;
        t1 = clock();
        float x = (float)(t1-t2);
        float y = x/CLOCKS_PER_SEC;
        float z = y*1000;
        t2 = t1;
      }
      /* sorting arrays for ascending order */
      if(ybots && ytops){
        array_sorter(ybots);
        array_sorter(ytops);
        min_diam = (ybots[0]-ytops[9])/scale_factor;
        max_diam = (ybots[9]-ytops[0])/scale_factor;
        avg_diam = (min_diam+max_diam)/2;
      }
      sprintf(display1_entry_text0,"Min   :    %.3g",min_diam);
      write(pfds[1], display1_entry_text0, 100);
      _exit(0);
    }
    else if(pID <0){
      printf("Failed to fork n");
      exit(1);
    }
    else{
      //parent process
      char buf[100];
      read(fpds[0], buf, 100);
      //updates the gtk interface with read value
      gtk_lable_set(data[0], buf);
      wait(NULL);
    }
    return TRUE;
}

**注意,我已经从实际的整个代码中粘贴了这段代码,而且这不会运行。粘贴在这里只是为了给我一些关于我正在努力实现的目标的想法。

看起来您在父进程中阻止了readwait调用。换句话说,尽管您生成了一个子进程来执行计算,但在子进程完成之前,您仍然会阻止父进程。没有实现并行性。

我建议在进程中有一个工作线程来进行计算,并在结果可用时通知主线程。

在父进程/线程中,应该使管道的读取端不阻塞,并将其注册到事件循环中。一旦读取端准备好进行读取,请在非阻塞模式下读取所有数据。

SIGCHLD设置一个信号处理程序,并在其中调用wait以释放子进程资源。

相关内容

  • 没有找到相关文章

最新更新