linux GTK 多进程

来源:互联网 发布:windows tree命令详解 编辑:程序博客网 时间:2024/05/26 08:43

内容:编写一个C程序,使用Linux下的图形库,分窗口显示三个并发进程的运行。

一个linux下多进程的实例,同时练习GTK编程。

分三个文件,分别是创建进程到主函数threeProc.c、建立子进程窗口的函数procBar.h和另外一个畸形窗口创建函数showImage.h。

实验过程:编辑源程序,将三个源程序和一个图片置于一个文件夹中,执行如下命令:

注意命令:gcc -o sb *.c `pkg-config --cflags --libs gtk+-2.0`

        编译命令中使用的单引号类型是很重要的。这里使用了“命令替换”。
命令替换(command substitution)使得可以捕获一个命令的输出而在另一个命令中替换它。
这个单引号不是回车键左边的那个,而是ESC键下面的那个。



源程序及图片文件:(也可以直接打包下载:http://download.csdn.net/detail/creazyapple/4088119)


/* *  threeProc.c *  SystemMonitor *  Created on: 2012-2-22 *      Author: zhushengben * Create threee processes , * Each process have it's own window , and just simply show a lab * All the processes are synchronic. * Authored by ZhuShengben hust * 2012.2.14 */#include <stdio.h>#include <unistd.h>#include <gtk/gtk.h>#include "proBar.h"#include "showImage.h"/* * 如果你的 "delete_event" 信号处理函数返回 FALSE,GTK 会发出 "destroy" 信号。 */gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data){/* 打印信息 *///g_print("delete event occurred\n");gtk_main_quit();//return (TRUE);}/* destroy a window * 另一个回调函数 */void destroy(GtkWidget *widget, gpointer data){gtk_main_quit();}void initProcWind(int argc, char *argv[], char *pst){/* GtkWidget 是构件的存储类型 */GtkWidget * window;GtkWidget *vbox;/* 这个函数在所有的 GTK 程序都要调用。参数由命令行中解析出来并且送到该程序中*/gtk_init(&argc, &argv);/* Create a new window */window = gtk_window_new(GTK_WINDOW_TOPLEVEL);/* * 当窗口收到 "delete_event" 信号 (这个信号由窗口管理器发出,通常是“关闭” * 选项或是标题栏上的关闭按钮发出的),我们让它调用在前面定义的 delete_event() 函数。 * 传给回调函数的 data 参数值是 NULL,它会被回调函数忽略。 */gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event), NULL);/* G_CALLBACK (delete_event), NULL); *//* * 在这里我们连接 "destroy" 事件到一个信号处理函数。 * 对这个窗口调用 gtk_widget_destroy() 函数或在 "delete_event" 回调函数中返回 FALSE 值 * 都会触发这个事件。 */gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(destroy),NULL);/* 容器 */vbox = gtk_vbox_new(FALSE, 5);gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);gtk_container_add(GTK_CONTAINER(window), vbox);gtk_widget_show(vbox);createProgressBar(vbox, FALSE, FALSE);/* 最后一步是显示新创建的窗口 */gtk_widget_show(window);/* 所有的 GTK 程序必须有一个 gtk_main() 函数。程序运行停在这里 * 等待事件 (如键盘事件或鼠标事件) 的发生。*/gtk_main();}int main(int argc, char *argv[]){int pid_1, pid_2;/* 创建子进程直到创建成功 */while ((pid_1 = fork()) == -1);/* 处理创建的第一个子进程 */if (pid_1 == 0){initProcWind(argc, argv, "I'm the first sonProc");}/* 处理父进程 */else{/* 创建第二个子进程直到成功 */while ((pid_2 = fork()) == -1);/* 处理第二个子进程 */if (pid_2 == 0)initProcWind(argc, argv, "I'm the second sonProc");else{/* 创建第二个子进程直到成功 */while ((pid_2 = fork()) == -1);/* 处理第二个子进程 */if (pid_2 == 0)initProcWind(argc, argv, "I'm the second sonProc");else{/* 处理父进程 */showImage(argc, argv);}}}return 0;}
/* *  progressBar.h *  systemMonitor *  Created on: 2012-2-19 *      Author: zhushengben */#ifndef PROGRESSBAR_H_#define PROGRESSBAR_H_typedef struct ProgressData{GtkWidget *pbar;int timer;gboolean activity_mode;gboolean showCpuProgress;} ProgressData;/* 更新进度条,这样就能够看到进度条的移动 */gint progress_timeout(gpointer data){ProgressData *pdata = (ProgressData *) data;gdouble new_val;if (pdata->activity_mode)gtk_progress_bar_pulse(GTK_PROGRESS_BAR(pdata->pbar));else{/* 使用在调整对象中设置的取值范围计算进度条的值 */new_val = gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(pdata->pbar))+ 0.01;if (new_val > 1.0)new_val = 0.0;gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pdata->pbar), new_val);}/* 这是一个 timeout 函数,返回 TRUE,这样它就能够继续被调用 */return TRUE;}/* 回调函数,切换在进度条你的滑槽上的文本显示 */void toggle_show_text(GtkWidget *widget, ProgressData *pdata){const gchar *text;text = gtk_progress_bar_get_text(GTK_PROGRESS_BAR(pdata->pbar));if (text && *text)gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pdata->pbar), "");elsegtk_progress_bar_set_text(GTK_PROGRESS_BAR(pdata->pbar), "Ereasing...");}/* 回调函数,切换进度条的活动模式 */void _toggle_activity_mode(GtkWidget *widget, ProgressData *pdata){pdata->activity_mode = !pdata->activity_mode;if (pdata->activity_mode)gtk_progress_bar_pulse(GTK_PROGRESS_BAR(pdata->pbar));elsegtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pdata->pbar), 0.0);}/* 回调函数,切换进度条的移动方向 */void toggle_orientation(GtkWidget *widget, ProgressData *pdata){switch (gtk_progress_bar_get_orientation(GTK_PROGRESS_BAR(pdata->pbar))){case GTK_PROGRESS_LEFT_TO_RIGHT:gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pdata->pbar),GTK_PROGRESS_RIGHT_TO_LEFT);break;case GTK_PROGRESS_RIGHT_TO_LEFT:gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pdata->pbar),GTK_PROGRESS_LEFT_TO_RIGHT);break;default:;// 什么也不做}}/* 清除分配的内存,删除定时器(timer) */void destroy_progress(GtkWidget *widget, ProgressData *pdata){gtk_timeout_remove(pdata->timer);pdata->timer = 0;g_free(pdata);}int createProgressBar(GtkWidget *vbox, gboolean activity_mode,gboolean left_right){ProgressData *pdata;GtkWidget *align;GtkWidget *separator;GtkWidget *table;GtkWidget *button;GtkWidget *check;/* 为传递到回调函数中的数据分配内存 */pdata = g_malloc(sizeof(ProgressData));pdata->showCpuProgress = left_right;/* 创建一个居中对齐的对象 */align = gtk_alignment_new(0.5, 0.5, 0, 0);gtk_box_pack_start(GTK_BOX(vbox), align, FALSE, FALSE, 5);gtk_widget_show(align);/* 创建进度条 */pdata->pbar = gtk_progress_bar_new();gtk_container_add(GTK_CONTAINER(align), pdata->pbar);pdata->activity_mode = activity_mode;gtk_widget_show(pdata->pbar);/* 加一个定时器(timer),以更新进度条的值 */pdata->timer = gtk_timeout_add(100, progress_timeout, pdata);separator = gtk_hseparator_new();gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, FALSE, 0);gtk_widget_show(separator);/* 行数、列数、同质性(homogeneous) */table = gtk_table_new(2, 2, FALSE);gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, TRUE, 0);gtk_widget_show(table);/* 添加一个复选按钮,以选择是否显示在滑槽里的文本 */check = gtk_check_button_new_with_label("show text");gtk_table_attach(GTK_TABLE(table), check, 0, 1, 0, 1,GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 5, 5);g_signal_connect(G_OBJECT(check), "clicked", G_CALLBACK(toggle_show_text),pdata);gtk_widget_show(check);/* 添加一个复选按钮,切换活动状态 */check = gtk_check_button_new_with_label("Activity mode");gtk_table_attach(GTK_TABLE(table), check, 0, 1, 1, 2,GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 5, 5);g_signal_connect(G_OBJECT(check), "clicked", G_CALLBACK(_toggle_activity_mode), pdata);gtk_widget_show(check);/* 添加一个复选按钮,切换移动方向 */check = gtk_check_button_new_with_label("Right to Left");gtk_table_attach(GTK_TABLE(table), check, 0, 1, 2, 3,GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 5, 5);g_signal_connect(G_OBJECT(check), "clicked",G_CALLBACK(toggle_orientation), pdata);gtk_widget_show(check);return 0;}#endif /* PROGRESSBAR_H_ */

/* *showImage.h */void showImage(int argc, char *argv[]){GtkWidget *window = NULL;GdkPixbuf *pixbuf = NULL;GdkBitmap *bitmap = NULL;GdkPixmap *pixmap = NULL;gtk_init(&argc, &argv);window = gtk_window_new(GTK_WINDOW_TOPLEVEL);gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(gtk_main_quit), NULL);gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gtk_main_quit), NULL);gtk_window_set_decorated(GTK_WINDOW(window), FALSE); // 设置无边框gtk_widget_set_app_paintable(window, TRUE);gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);gtk_widget_realize(window);pixbuf = gdk_pixbuf_new_from_file("penguin.gif", NULL); // gdk函数读取png文件gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap, &bitmap, 120); // alpha小于128认为透明gtk_widget_shape_combine_mask(window, bitmap, 0, 0); // 设置透明蒙板gdk_window_set_back_pixmap(window->window, pixmap, FALSE); // 设置窗口背景g_object_unref(pixbuf);g_object_unref(bitmap);g_object_unref(pixmap);gtk_widget_show_all(window);gtk_main();}

关于多进程:

    int pid;    /* 创建子进程直到创建成功 */    while ((pid_1 = fork()) == -1)        ;    /* fork 创建进程,返回值有三种:     * pid == -1 表示创建没成功     * pid == 0 表示子进程     * pid > 0 表示父进程 */    if (pid_1 == 0)    {    //处理创建的子进程    }    else    {    //父进程处理程序    }

在本例中,我首先用procBar.h中的函数创建三个普通窗口,每个窗口添加一个进度条控件,每个控件设置3个参数来控制它。最后再用showImage.h中的函数创建另外一个窗口。注意,前三个普通窗口共享一段代码,但是他们的三个控制参数互补干扰,由此可见进程的特点:一段程序可以对应多个进程,进程是程序的动态表现,同时也可见进程与线程的区别:每个进程的资源是独立的,进程是资源分配的最小单位。