GtkD code review - How to update a progressbar using data sharing concurrency
adnan338
relay.dev.adnan at protonmail.com
Sat Jun 20 16:30:18 UTC 2020
Hello, I need a code review on my strategy of updating a GtkD
progressbar. Gtk is not thread safe, I interpret that as "I must
only access data available in the main thread from the Gtk
objects".
This example is a simplified excerpt of my project. I have never
done concurrency before and thus I would like a code review. The
goal here is
1. Downloading a list of file in parallel
2. Update the gtk progressbar periodically to show the overall
download progress.
import gio.Application : GioApplication = Application;
import gtk.Application : Application;
import gtk.ApplicationWindow : ApplicationWindow;
import gtk.ProgressBar : ProgressBar;
import glib.Timeout : Timeout;
import gtkc.gtktypes : GApplicationFlags, GPriority;
class Downloader
{
string[] links = [`link1`, `link2`, `link3`, `link4`];
private shared size_t completed = 0;
double getFraction()
{
return cast(double) completed / links.length;
}
static void start(ref Downloader downloader)
{
import std.parallelism : parallel;
import core.thread : Thread, seconds;
{
// emulate HTTP response overhead;
Thread.sleep(seconds(2));
}
synchronized
{
// emulate random Download time
import std.random : Random, uniform;
auto rnd = Random(4361);
foreach (_; downloader.links.parallel())
{
Thread.sleep(uniform(0, 6, rnd).seconds());
++cast() downloader.completed;
}
}
}
}
class ProgressIndicatorBar : ProgressBar
{
this()
{
super.setShowText(true);
super.setPulseStep(0.2);
}
}
class PrimaryWindow : ApplicationWindow
{
const int width = 320, height = 100;
ProgressIndicatorBar pib;
this(Application app)
{
super(app);
super.setSizeRequest(width, height);
scope (success)
super.showAll();
pib = new ProgressIndicatorBar();
scope (success)
add(pib);
auto downloader = new Downloader();
import std.parallelism : task;
auto downloadTask = task!(Downloader.start)(downloader);
downloadTask.executeInNewThread();
auto timeout = new Timeout(100, delegate bool() {
if (downloader.completed < downloader.links.length)
{
if (downloader.completed == 0)
{
pib.setText(`Awaiting response...`);
pib.pulse();
}
else
{
pib.setText(`Downloading...`);
pib.setFraction(downloader.getFraction());
}
return true;
}
else
{
super.setTitle(`Downloading complete`);
// pib.setShowText(false);
pib.setVisible(false);
return false;
}
}, GPriority.HIGH);
}
}
int main(string[] args)
{
auto application = new
Application(`org.gitlab.helloprogressbar`,
GApplicationFlags.FLAGS_NONE);
application.addOnActivate(delegate void(GioApplication app) {
auto appWindow = new PrimaryWindow(application);
});
return application.run(args);
}
More information about the Digitalmars-d-learn
mailing list