- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
Mandelbrot 生成器的慢速多精度实现。线程化,使用 POSIX 线程。 Gtk 图形用户界面。
我有点迷路了。这是我第一次尝试编写线程程序。我实际上还没有尝试转换它的单线程版本,只是尝试实现基本框架。
到目前为止它是如何工作的简要说明:
Main 创建 watch_render_start 线程,它等待 pthread_cond_signal,当“渲染”按钮被点击时,GUI 回调会发出信号。
watch_render_start 检查图像是否已经在渲染,检查退出等,但如果一切顺利,它会创建 render_create_threads 线程。
render_create_threads 线程然后创建渲染线程,然后使用 pthread_join 等待它们完成(并使用 get_time_of_day 做一些计时工作——这在线程中很糟糕吗?)。
渲染线程的入口点(想象中)称为 render,循环,而 next_line 计算函数返回 TRUE 以处理更多行。在这个 while 循环中,检查停止或退出。
next_line 函数获取要计算的行,然后递增变量以指示下一个线程要计算的下一行。如果要处理的行超出图像高度,它会返回。如果不是,则它计算该行的内容。然后递增 lines_done 并根据图像的高度检查它,如果 >= 则返回 0,如果 <.
则返回 1这里是全部 470 多行代码,我相信您会从中获得乐趣。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <mpfr.h>
#include <string.h>
#include <gtk/gtk.h>
#include <sys/time.h>
/* build with:
gcc threaded_app.c -o threaded_app -Wall -pedantic -std=gnu99 -lgmp -lmpfr -pthread -D_REENTRANT -ggdb `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`
*/
typedef struct
{
struct timeval tv_start;
struct timeval tv_end;
} Timer;
void timer_start(Timer* t)
{
gettimeofday(&t->tv_start, 0);
}
void timer_stop(Timer* t)
{
gettimeofday(&t->tv_end, 0);
}
long timer_get_elapsed(Timer* t)
{
if (t->tv_start.tv_sec == t->tv_end.tv_sec)
return t->tv_end.tv_usec - t->tv_start.tv_usec;
else
return (t->tv_end.tv_sec - t->tv_start.tv_sec) *
1e6 + (t->tv_end.tv_usec - t->tv_start.tv_usec);
}
#define NTHREADS 8
#define IMG_WIDTH 480
#define IMG_HEIGHT 360
typedef struct
{
int rc;
pthread_t thread;
} rthrds;
typedef struct
{
int* arr;
int next_line;
int lines_done;
int rendering;
int start;
int stop;
pthread_t rend[NTHREADS];
int all_quit;
int width;
int height;
double xmin, xmax, ymax;
int depth;
} image_info;
static gboolean delete_event(GtkWidget *widget,
GdkEvent *event,
gpointer data);
static void destroy(GtkWidget *widget, gpointer data);
void gui_start_render(GtkWidget* widget, gpointer data);
void gui_stop_render(GtkWidget* widget, gpointer data);
static GtkWidget* gui_pbar = NULL;
void *render(void* ptr);
int next_line(image_info* img);
void* watch_render_start(void* ptr);
void* watch_render_stop(void* ptr);
void* watch_render_done(void* ptr);
void* threads_render_create(void* ptr);
pthread_mutex_t next_line_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lines_done_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t img_start_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t img_stop_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t img_rendering_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t img_start_cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t img_stop_cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t img_done_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t all_quit_mutex = PTHREAD_MUTEX_INITIALIZER;
int main(int argc, char **argv)
{
printf("initializing...\n");
image_info* img = malloc(sizeof(image_info));
memset(img, 0, sizeof(image_info));
img->start = 0;
img->width = IMG_WIDTH;
img->height = IMG_HEIGHT;
img->xmin = -0.75509089265046296296296259;
img->xmax = -0.75506025752314814814814765;
img->ymax = 0.050215494791666666666666005;
img->depth = 30000;
size_t arr_size = img->width * img->height * sizeof(int);
printf("creating array size: %ld bytes\n", arr_size);
img->arr = malloc(arr_size);
if (!img->arr)
{
fprintf(stderr, "image dimension too large!\n");
free(img);
exit(-1);
}
memset(img->arr, 0, arr_size);
int rc_err;
pthread_t thread_start;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
printf("creating watch render start thread...\n");
rc_err = pthread_create(&thread_start, &attr,
&watch_render_start, (void*)img);
if (rc_err)
{
fprintf(stderr, "Thread start creation failed: %d\n",
rc_err);
free(img->arr);
free(img);
exit(-1);
}
printf("creating GUI...\n");
GtkWidget *window;
GtkWidget *startbutton;
GtkWidget *stopbutton;
GtkWidget *box1;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (destroy), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
box1 = gtk_hbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), box1);
startbutton = gtk_button_new_with_label ("Start render");
g_signal_connect (G_OBJECT (startbutton), "clicked",
G_CALLBACK (gui_start_render), img);
gtk_box_pack_start(GTK_BOX(box1), startbutton, TRUE, TRUE, 0);
stopbutton = gtk_button_new_with_label ("Stop render");
g_signal_connect (G_OBJECT (stopbutton), "clicked",
G_CALLBACK (gui_stop_render), img);
gtk_box_pack_start(GTK_BOX(box1), stopbutton, TRUE, TRUE, 0);
gui_pbar = gtk_progress_bar_new();
gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(gui_pbar),
GTK_PROGRESS_LEFT_TO_RIGHT);
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(gui_pbar),
(gfloat)1.0 ); /* img->real_height); */
gtk_widget_set_size_request(gui_pbar, 75, 0);
gtk_box_pack_end(GTK_BOX(box1), gui_pbar, FALSE, FALSE, 0);
gtk_widget_show(startbutton);
gtk_widget_show(stopbutton);
gtk_widget_show(box1);
gtk_widget_show(window);
printf("starting GUI\n");
gtk_main ();
printf("************************\n"
"GUI shutdown\n"
"************************\n");
printf("setting all_quit\n");
pthread_mutex_lock(&all_quit_mutex);
img->all_quit = 1;
pthread_mutex_unlock(&all_quit_mutex);
printf("signalling watch render start thread to wakeup...\n");
pthread_mutex_lock(&img_start_mutex);
pthread_cond_signal(&img_start_cond);
pthread_mutex_unlock(&img_start_mutex);
printf("waiting for watch render start thread to quit...\n");
pthread_join(thread_start, NULL);
printf("done\n");
printf("freeing memory\n");
free(img->arr);
free(img);
printf("goodbye!\n");
exit(0);
}
void gui_start_render(GtkWidget* widget, gpointer ptr)
{
image_info* img = (image_info*)ptr;
printf("************\n"
"GUI signalling to start render...\n"
"************\n");
pthread_mutex_lock(&img_start_mutex);
img->start = 1;
pthread_cond_signal(&img_start_cond);
pthread_mutex_unlock(&img_start_mutex);
}
void gui_stop_render(GtkWidget* widget, gpointer ptr)
{
image_info* img = (image_info*)ptr;
printf("************\n"
"GUI signalling to stop render...\n"
"************\n");
pthread_mutex_lock(&img_stop_mutex);
img->stop = 1;
pthread_mutex_unlock(&img_stop_mutex);
}
void* watch_render_start(void* ptr)
{
image_info* img = (image_info*)ptr;
int rc_err;
pthread_t render_thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int r;
int quit = 0;
for(;;)
{
printf("watch_render_start: waiting for img_start_cond\n");
pthread_mutex_lock(&img_start_mutex);
if (!img->start)
pthread_cond_wait(&img_start_cond, &img_start_mutex);
img->start = 0;
pthread_mutex_unlock(&img_start_mutex);
printf("watch_render_start: recieved img_start_cond\n");
pthread_mutex_lock(&img_rendering_mutex);
r = img->rendering;
pthread_mutex_unlock(&img_rendering_mutex);
printf("checking if we are rendering... ");
if (r)
{
printf("yes\nStopping render...\n");
pthread_mutex_lock(&img_stop_mutex);
img->stop = 1;
pthread_cond_signal(&img_stop_cond);
pthread_mutex_unlock(&img_stop_mutex);
pthread_join(render_thread, NULL);
printf("render stopped\n");
}
else
printf("no\n");
pthread_mutex_lock(&all_quit_mutex);
quit = img->all_quit;
pthread_mutex_unlock(&all_quit_mutex);
if (quit)
{
printf("exiting watch render start thread\n");
pthread_exit(0);
}
printf("creating render thread...\n");
rc_err = pthread_create(&render_thread, &attr,
&threads_render_create, (void*)img);
if (rc_err)
pthread_exit(0);
}
}
void* threads_render_create(void* ptr)
{
Timer timing_info;
printf("initializing render thread\n");
image_info* img = (image_info*)ptr;
pthread_mutex_lock(&img_rendering_mutex);
img->rendering = 1;
pthread_mutex_unlock(&img_rendering_mutex);
pthread_mutex_lock(&lines_done_mutex);
img->lines_done = 0;
pthread_mutex_unlock(&lines_done_mutex);
pthread_mutex_lock(&img_stop_mutex);
img->stop = 0;
pthread_mutex_unlock(&img_stop_mutex);
pthread_mutex_lock(&next_line_mutex);
img->next_line = 0;
pthread_mutex_unlock(&next_line_mutex);
int rc_err, i;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
timer_start(&timing_info);
for (i = 0; i < NTHREADS; ++i)
{
printf("creating renderer thread #%d...\n", i);
rc_err = pthread_create(&img->rend[i], &attr,
&render, (void*)img);
if (rc_err)
{
fprintf(stderr, "\nrender thread #%d creation failed: %d\n",
i, rc_err);
return 0;
}
}
for (i = 0; i < NTHREADS; ++i)
{
printf("joining renderer thread #%d...\n", i);
pthread_join(img->rend[i], NULL);
}
timer_stop(&timing_info);
printf("render-time %.3fs\n\n",
timer_get_elapsed(&timing_info) / (double)1e6);
printf("all renderer threads finished\n");
pthread_mutex_lock(&img_stop_mutex);
img->stop = 0;
pthread_mutex_unlock(&img_stop_mutex);
pthread_mutex_lock(&img_rendering_mutex);
img->rendering = 0;
pthread_mutex_unlock(&img_rendering_mutex);
printf("at end of threads_render_create\n");
pthread_mutex_lock(&lines_done_mutex);
if (img->lines_done >= img->height)
printf("image complete\n");
else
printf("image interuppted\n");
pthread_mutex_unlock(&lines_done_mutex);
pthread_mutex_lock(&img_start_mutex);
img->start = 0;
pthread_mutex_unlock(&img_start_mutex);
printf("exiting render thread\n");
pthread_exit(NULL);
}
void* render(void* ptr)
{
image_info* img = (image_info*)ptr;
int quit = 0;
printf("starting render..\n");
while(next_line(img) && !quit)
{
pthread_mutex_lock(&img_stop_mutex);
quit = img->stop;
pthread_mutex_unlock(&img_stop_mutex);
pthread_mutex_lock(&all_quit_mutex);
quit |= img->all_quit;
pthread_mutex_unlock(&all_quit_mutex);
}
printf("exiting render thread\n");
pthread_exit(0);
}
int next_line(image_info* img)
{
int line;
pthread_mutex_lock(&next_line_mutex);
line = img->next_line++;
pthread_mutex_unlock(&next_line_mutex);
if (line >= img->height)
return 0;
int ix,wz;
int img_width = img->width;
long double x,y,x2,y2,wre=0,wim=0,wre2=0,wim2=0;
long double xmin = img->xmin, xmax = img->xmax, ymax = img->ymax;
long double xdiff = xmax - xmin;
int depth = img->depth;
long double c_im = 0, c_re = 0;
y = ymax - (xdiff / (long double)img_width)
* (long double)line;
y2 = y * y;
for (ix = 0; ix < img_width; ++ix)
{
x = ((long double)ix / (long double)img_width) * xdiff + xmin;
x2 = x * x;
wre = x;
wim = y;
wre2 = x2;
wim2 = y2;
for (wz = 0; wz < depth; ++wz)
{
wim = 2.0 * wre * wim + c_im;
wre = wre2 - wim2 + c_re;
wim2 = wim * wim;
wre2 = wre * wre;
if (wim2 + wre2 > 4.0F)
break;
}
if (wz == depth + 1)
wz = 0;
img->arr[line * img_width + ix] = wz;
}
printf("line %d complete\n", line);
pthread_mutex_lock(&lines_done_mutex);
img->lines_done++;
if (img->lines_done == img->height)
{
pthread_mutex_unlock(&lines_done_mutex);
return 0;
}
pthread_mutex_unlock(&lines_done_mutex);
return 1;
}
static gboolean delete_event(GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
return FALSE;
}
static void destroy(GtkWidget *widget, gpointer data)
{
gtk_main_quit ();
}
我已经走到这一步了,需要一些关于如何继续的指导。对于我面临的每个问题,我只是看到一个令人困惑的解决方案迷宫,通向死胡同!
我想先解决进度条问题。 gui 需要锁定 lines_done。但是怎么知道什么时候该做呢?它多久查看一次 lines_done?我想我可以为此使用 g_idle_add。
然后是实际呈现所有这些快乐线程正在生成的数据的真正肉质问题。正如在另一个问题上所讨论的,我将有一组标志来指示实际呈现的行(因为由于线程和操作系统调度程序的性质,它们将以任意顺序呈现)。但是 GUI 将如何检查这些呢?在与进度条相同的空闲回调中?假设正在生成一个 8000 像素高的大图像,那就是每隔这么多毫秒就有 8000 个互斥锁和解锁 - 这一定是有成本的吧?
那么我该如何进行呢?我正在使用的这个模型,无论它是什么,是否能够做我想做的事?
最佳答案
如果您可以在您的平台上访问原子读取和原子写入,那么创建一个工作分配表(阅读您平台的体系结构说明 - 普通读取和写入可能足够好,也可能不够好,你可能需要也可能不需要添加内存屏障):
每行一个字节,初始为零,非零表示该行分配给的线程
...并为每个工作线程创建一个自动更新的完成行数 int 字段。应使用原子读/写指令更新和读取该表(根据平台上的可用指令,以 8、16、32 或 64 位的 block 形式)。
顶层逻辑必须确定是直接在主线程上完成所有工作(如果图像真的很小),还是启动一个工作线程,或者启动 N 个工作线程。
协调线程(或者如果是我,我可能会放弃协调线程并在主线程上执行此操作)将循环法中的一半工作分配给线程(如果少于一定数量,则分配所有工作).如果它分配的工作量少于所有工作量,它就会监视其他线程并对平均线程和最佳线程的性能进行基准测试。它确保线程作为一个整体不会耗尽工作,但尽量不让线程无事可做。
前端为每个 worker 保留一个指针,指向 worker 在分配表中完成的位置,当 worker 增加其整数字段以表示它完成了多少行时,前端会向前搜索工作分配表查找分配给该 worker 的工作的行索引,现在已完成,并更新完成特定行的位缓冲区,并更新总完成字段。
--
这是将工作动态分配给线程的通用算法,正如另一位发帖人所建议的那样,您也可以通过使工作线程应处理的行号成为工作线程数和工作线程数的函数来静态分配工作线程数,然后通过原子字段将每个工作人员完成的行数传递给前端。
关于c - 我的线程图像生成应用程序如何将其数据获取到 gui?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2035758/
我有一个无 GUI 的服务器(没有任何桌面环境或 Ubuntu 服务器的新鲜 Debian,没有 X 服务器,先验)。 我考虑安装 docker 并拉取一个基于官方 Ubuntu 的容器,并在其上添加
我正在构建一个带有临时用户名系统的简单聊天服务器。当屏幕弹出时,首先会出现一个简单的屏幕,询问您的用户名。你可以放入任何你想要的东西,这纯粹是暂时的(我也在尝试)。代码告诉程序继续,将用户名保存到代码
我想将来自其他类的图像显示到 QLabel 中,但要通知 GUI 有一个新的框架可用。我需要从非 GUI 类和非 GUI 线程发出信号。 有什么办法吗? 最佳答案 signal 可以从任何继承QObj
我正在用 Java 编写一个图形用户界面,它有一些按钮,其中一个按钮是选项。我想要它,所以当您单击选项时,它会将 gui 更改为我的选项 gui,而不是在另一个窗口中打开它。 我该怎么做? 最佳答案
标题说明了一切...我和我的 friend 正在这样做,我们不知道为什么 Ball.java 实际上没有在 gamePanel 中制作球,然后制作 GUI。顺便说一句,这是 8 球台球。这是代码: 驱
我正在使用 GUI 构建器,我想知道是否有一种简单的方法可以通过当前主窗口打开寄存器窗口(引用下面的页面)。我正在尝试通过菜单栏来执行此操作。 我一整天都在尝试,因为 GUI Builder 生成了一
我有一个程序使用了许多隐藏的 GUI 组件。例如,所有菜单项和打印机对话框/组件(仅占用至少 50 毫秒)。总的来说,我猜整个程序启动的大约 300 毫秒(或 40%)要归功于所有隐藏的东西。 我想做
我对 GUI 构建比较陌生。 我想制作一个带有按钮(我已经有了)的 GUI,用户可以按下该按钮并选择一个图像,然后动态地将该图像加载到面板中的 GUI 中。我希望每次用户浏览图像时图像都动态变化。 到
我有两年使用 Java 和 Visual Studio 进行企业应用程序编程的经验,而且我是 Python 和 wxPython 的新手。所以我的问题是:wxPython 能否为我提供足够丰富的 GU
这是我启动 mkvtoolnix-gui 时遇到的错误: mkvtoolnix-gui: symbol lookup error: mkvtoolnix-gui: undefined symbol:
我在初始屏幕上有一些最近使用的存储库,我想删除它们,因为我不再使用它们了。如何删除它们? 操作系统 = Windows 7 我查看了注册表并搜索了 git 目录,但找不到最近使用列表的存储位置。 最佳
我正在尝试在 matlab、GUI 中用户输入点作为输入和它们之间的连接。 我有 5 个 matlab 文件 - screen1.m、screen2.m、screen3.m、screen4.m、glo
我用java制作了一个客户端/服务器程序,我已经按照我想要的方式使用cmd完美地工作了,现在我正在尝试将代码的客户端转换为GUI,但是我在打印时遇到问题客户端消息并从文本字段和服务器消息读取客户端输入
我正在制作一种 CRUD 应用程序(Java GUI,MYSQL)我应该: 将数据从数据库加载到List(例如),然后将List加载到GUI 将数据从数据库加载到对象(具有 SQL 表等属性)和对象到
我正在开发一个有 5 个图形用户界面窗口的 Java 应用程序,其中一个是问候窗口或主窗口,我已经完成了所有逻辑部分的工作,我已经完成了 99.99%,唯一剩下的就是我如何以这种方式编码,当我点击一个
我目前正在开发 GUI。 我选择将我的 GUI 基于 bluej 项目 - Scribble。 当您创建 ScribbleGUI 对象时,DrawDemo 类会创建一个同时自动打开的 Canvas 。
在这里阅读了很多关于多进程、管道等的内容后,我还没有找到答案,但如果它已经存在,我深表歉意。 我有一个外围硬件,我正在尝试为其创建一个 GUI。我想让 GUI 使用来自外围设备的数据不断更新,同时仍保
我想做的是将 GUI 从一个单独文件中的类链接到另一个类。我的第一个类是一个主菜单,它将显示一些链接到另一个窗口的按钮。第二个类显示不同的窗口,但我现在遇到的问题是我不知道如何链接第一个类中的按钮来调
我的 GUI 代码中有一个奇怪的行为。如果用户在短时间内产生大量事件,则可能会发生正在运行的事件处理程序方法被另一个事件处理程序方法中断。由于一切都在同一个线程(GUI 线程)中运行,所以一切都应该按
这是一个涉及风格的问题。我正在寻找可以帮助我解决常见 GUI 设计问题 的想法。该应用程序是在 Winforms 中完成的,宁愿使用 WPF,该应用程序已经完成,但我是一个完美主义者,在与其他人合作时
我是一名优秀的程序员,十分优秀!