View previous topic :: View next topic |
Author |
Message |
GG
Joined: 05 Nov 2009 Posts: 18
|
Posted: Sun Dec 06, 2009 9:50 am Post subject: D_Version2 and gdk.Threads |
|
|
Is it true that gdk.Threads is not compatible with D_Version2(I'm using dmd2.036 and GtkD1.3).
Because I try to make test application with a thread that listen a socket client to update a TextView (like chat), but event if I use Main.initMultiThread(args) before gtk.main(), and gdkThreadsEnter and gdkThreadsLeave around textview.insertText("...") in RUN method of the thread, the application crashes with Segmentation fault (core dumped), doesn't it?
Has anybody ever achieved it with Thread application ?
Thanks ! |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Sun Dec 06, 2009 10:18 am Post subject: |
|
|
Are you using Linux or Windows, since the gdk threads don't work on windows.
The segfault would suggest Linux, where it should work, but i haven't tested with the latest compiler yet. |
|
Back to top |
|
|
GG
Joined: 05 Nov 2009 Posts: 18
|
Posted: Sun Dec 06, 2009 10:30 am Post subject: |
|
|
I'm using Linux,
Code source client.d:
module client;
import std.stdio;
import std.socket;
import std.string;
import std.conv;
import gtk.Builder;
import gtk.Main;
import gtk.Window;
import gtk.Widget;
import gtk.TextView;
import gtk.TextBuffer;
import gdk.Keymap;
import std.encoding;
import gdk.Threads;
import core.thread;
class ClassClient
{
private Builder app;
private Window w;
private TextView txtvSend;
private TextBuffer txtBufferSend;
private Socket s_client;
public TextView txtvRcv;
this(Socket s)
{
s_client = s;
app = new Builder();
auto err = app.addFromFile("client.glade");
if(err == 0 ) {
writefln("Error opening glade file.");
}
else
{
auto obj = app.getObject("window1");
obj.setData("GObject", null);
w = new Window(cast(GtkWindow*)obj.getObjectGStruct());
if(w !is null) {
obj = app.getObject("textviewSend");
obj.setData("GObject",null);
txtvSend = new TextView(cast(GtkTextView*)obj.getObjectGStruct());
txtvSend.addOnKeyPress(&onKeyPressSend);
obj = app.getObject("bufferSend");
obj.setData("GObject",null);
txtBufferSend = new TextBuffer(cast(GtkTextBuffer*)obj.getObjectGStruct());
obj = app.getObject("textviewRcv");
obj.setData("GObject",null);
txtvRcv = new TextView(cast(GtkTextView*)obj.getObjectGStruct());
w.show();
w.addOnHide( delegate void(Widget aux){ Main.exit(0); } );
Thread th_client = new Th_client();
th_client.start();
}
else { writefln("Error launching application."); }
}
}
bool onKeyPressSend( GdkEventKey* event, Widget widget )
{
if(event.state & GdkModifierType.SHIFT_MASK)
{
if(Keymap.gdkKeyvalName(event.keyval) == "Return")
return false;
}
if(Keymap.gdkKeyvalName(event.keyval) == "Return")
{
sendToAll();
return true;
}
return false;
}
void sendToAll()
{
char[1024] buf = void;
int read = s_client.send(cast(const char[])txtBufferSend.getText());
txtBufferSend.setText("");
writefln("%d",read);
s_client.receive(buf);
writefln("%s",buf[0..read]);
/*string temp = "";
transcode(cast(Latin1String)to!string(buf[0..read]),temp);
txtvRcv.insertText(temp~"\r");*/
}
class Th_client : Thread
{
this()
{
super( &run );
}
~this()
{
//writefln("killed id = %d",id);
}
private void run()
{
char[1024] buf = void;
while(true)
{
int read = s_client.receive(buf);
if(Socket.ERROR == read)
{
writefln("connection error");
break;
}
else if (read==0)
{
try
{
//if the connection closed due to an error, remoteAddress() could fail
writefln("Connection from %s closed.\n", s_client.remoteAddress().toString());
}
catch
{
}
break;
}
else
{
writefln("Received %d bytes from %s: %s", read, s_client.remoteAddress().toString(), buf[0 .. read]);
string temp = "";
transcode(cast(Latin1String)to!string(buf[0..read]),temp);
gdkThreadsEnter();
txtvRcv.insertText("Hello"~"\r");
gdkThreadsLeave();
}
}
}
}
}
class MyInternetAddress: InternetAddress
{
this(string addr, ushort port)
{
sin.sin_family = AddressFamily.INET;
super(addr, port);
}
this(uint addr, ushort port)
{
sin.sin_family = AddressFamily.INET;
super(addr, port);
}
this(ushort port)
{
sin.sin_family = AddressFamily.INET;
super(port);
}
}
int main (string[] args)
{
Main.initMultiThread(args);
string domain;
ushort port;
if(args.length >= 3)
{
domain = to!string(args[1]);
port = to!ushort(args[2]);
}
else
{
domain = "127.0.0.1";
port = 4444;
}
Socket s_client = new TcpSocket(new MyInternetAddress(domain, port));
assert(s_client.isAlive);
new ClassClient(s_client);
Main.run();
return 0;
}
If we can't create thread application with gtk.Threads, there is another solution ? I think about ProgressBar also.
Thanks ! |
|
Back to top |
|
|
GG
Joined: 05 Nov 2009 Posts: 18
|
Posted: Sun Dec 06, 2009 9:47 pm Post subject: |
|
|
Using GTK+2.18.3, DMD2.37, GtkD1.3, compile and get same problem.
Is there a problem of compatibility between them?
After long investigation, I discovered this when my application loads library:
Loaded lib = libatk-1.0.so
Loaded lib = libgtk-x11-2.0.so
Loaded lib = libgmodule-2.0.so
Loaded lib = libgdk-x11-2.0.so
Loaded lib = libgio-2.0.so
Loaded lib = libgobject-2.0.so
Loaded lib = libglib-2.0.so
Loaded lib = libgdk_pixbuf-2.0.so
Loaded lib = libcairo.so
Loaded lib = libgthread-2.0.so
Loaded lib = libpango-1.0.so
Loaded lib = libpangocairo-1.0.so
failed (libgio-2.0.so) g_io_module_load
failed (libgio-2.0.so) g_io_module_unload
failed (libglib-2.0.so) g_atomic_int_inc
failed (libglib-2.0.so) g_atomic_int_dec_and_test
failed (libglib-2.0.so) g_io_channel_win32_new_fd
failed (libglib-2.0.so) g_io_channel_win32_new_socket
failed (libglib-2.0.so) g_io_channel_win32_new_messages
failed (libglib-2.0.so) g_ascii_isalnum
failed (libglib-2.0.so) g_ascii_isalpha
failed (libglib-2.0.so) g_ascii_iscntrl
failed (libglib-2.0.so) g_ascii_isdigit
failed (libglib-2.0.so) g_ascii_isgraph
failed (libglib-2.0.so) g_ascii_islower
failed (libglib-2.0.so) g_ascii_isprint
failed (libglib-2.0.so) g_ascii_ispunct
failed (libglib-2.0.so) g_ascii_isspace
failed (libglib-2.0.so) g_ascii_isupper
failed (libglib-2.0.so) g_ascii_isxdigit
failed (libglib-2.0.so) g_win32_error_message
failed (libglib-2.0.so) g_win32_getlocale
failed (libglib-2.0.so) g_win32_get_package_installation_directory
failed (libglib-2.0.so) g_win32_get_package_installation_directory_of_module
failed (libglib-2.0.so) g_win32_get_package_installation_subdirectory
failed (libglib-2.0.so) g_win32_get_windows_version
failed (libglib-2.0.so) g_win32_locale_filename_from_utf8
failed (libgthread-2.0.so) g_mutex_new
failed (libgthread-2.0.so) g_mutex_lock
failed (libgthread-2.0.so) g_mutex_trylock
failed (libgthread-2.0.so) g_mutex_unlock
failed (libgthread-2.0.so) g_mutex_free
failed (libgthread-2.0.so) g_static_mutex_lock
failed (libgthread-2.0.so) g_static_mutex_trylock
failed (libgthread-2.0.so) g_static_mutex_unlock
failed (libgthread-2.0.so) g_static_mutex_get_mutex
failed (libgthread-2.0.so) g_cond_new
failed (libgthread-2.0.so) g_cond_signal
failed (libgthread-2.0.so) g_cond_broadcast
failed (libgthread-2.0.so) g_cond_wait
failed (libgthread-2.0.so) g_cond_timed_wait
failed (libgthread-2.0.so) g_cond_free
failed (libgthread-2.0.so) g_private_new
failed (libgthread-2.0.so) g_private_get
failed (libgthread-2.0.so) g_private_set
failed (libgthread-2.0.so) g_thread_supported
failed (libgthread-2.0.so) g_thread_create
failed (libgthread-2.0.so) g_thread_yield
failed (libpango-1.0.so) script_engine_list
failed (libpango-1.0.so) script_engine_init
failed (libpango-1.0.so) script_engine_exit
failed (libpango-1.0.so) script_engine_create
Same problem with demo "TestWindow" of GtkD, application got segmentation fault when it arrives on "gdkThreadsEnter()".
Is there a solution ?
I can't imagine me work with application without threading !
Thanks ! |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Mon Dec 07, 2009 12:46 pm Post subject: |
|
|
Could you post a backtrace i seen to have problems with my debugger |
|
Back to top |
|
|
GG
Joined: 05 Nov 2009 Posts: 18
|
Posted: Mon Dec 07, 2009 2:47 pm Post subject: |
|
|
hum, I'm using DMD2 as compiler, and I think there is no backtrace within. Can I do something as : debug scope( failure ) writef("Backtrace xx "__FILE__"(",__LINE__,")\n");
Is it enought?
I've never used a debugger with D, what debugger can I use ?
Another point attracted me, when I compile:
dmd -v client.o -ofClient -L-ldl -L-lgtkd
GIVE:
gcc client.o -o Client -m32 -ldl -lgtkd -Xlinker -L/etc/../lib -Xlinker -L/etc/../usr/local/lib -lphobos2 -lpthread -lm
Default library used here is -lpthread, what about -lgthread-2.0 ?
If I want remove -lpthread by -lgthread, it is possible ?
Thanks ! |
|
Back to top |
|
|
GG
Joined: 05 Nov 2009 Posts: 18
|
Posted: Mon Dec 07, 2009 4:01 pm Post subject: |
|
|
Okey ! I decided to use gdb as debugger and it gives me:
[Thread debugging using libthread_db enabled]
warning: .dynamic section for "/usr/lib/libcairo.so.2" is not at the expected address
warning: difference appears to be caused by prelink, adjusting expectations
warning: .dynamic section for "/usr/lib/libpixman-1.so.0" is not at the expected address
warning: difference appears to be caused by prelink, adjusting expectations
warning: .dynamic section for "/usr/lib/libatk-1.0.so.0" is not at the expected address
warning: difference appears to be caused by prelink, adjusting expectations
warning: .dynamic section for "/usr/lib/libgthread-2.0.so" is not at the expected address
warning: difference appears to be caused by prelink, adjusting expectations
Loaded lib = libatk-1.0.so
Loaded lib = libgtk-x11-2.0.so
Loaded lib = libgmodule-2.0.so
Loaded lib = libgdk-x11-2.0.so
Loaded lib = libgio-2.0.so
Loaded lib = libgobject-2.0.so
Loaded lib = libglib-2.0.so
Loaded lib = libgdk_pixbuf-2.0.so
Loaded lib = libcairo.so
Loaded lib = libgthread-2.0.so
Loaded lib = libpango-1.0.so
Loaded lib = libpangocairo-1.0.so
failed (libgio-2.0.so) g_io_module_load
failed (libgio-2.0.so) g_io_module_unload
failed (libglib-2.0.so) g_atomic_int_inc
failed (libglib-2.0.so) g_atomic_int_dec_and_test
failed (libglib-2.0.so) g_io_channel_win32_new_fd
failed (libglib-2.0.so) g_io_channel_win32_new_socket
failed (libglib-2.0.so) g_io_channel_win32_new_messages
failed (libglib-2.0.so) g_ascii_isalnum
failed (libglib-2.0.so) g_ascii_isalpha
failed (libglib-2.0.so) g_ascii_iscntrl
failed (libglib-2.0.so) g_ascii_isdigit
failed (libglib-2.0.so) g_ascii_isgraph
failed (libglib-2.0.so) g_ascii_islower
failed (libglib-2.0.so) g_ascii_isprint
failed (libglib-2.0.so) g_ascii_ispunct
failed (libglib-2.0.so) g_ascii_isspace
failed (libglib-2.0.so) g_ascii_isupper
failed (libglib-2.0.so) g_ascii_isxdigit
failed (libglib-2.0.so) g_win32_error_message
failed (libglib-2.0.so) g_win32_getlocale
failed (libglib-2.0.so) g_win32_get_package_installation_directory
failed (libglib-2.0.so) g_win32_get_package_installation_directory_of_module
failed (libglib-2.0.so) g_win32_get_package_installation_subdirectory
failed (libglib-2.0.so) g_win32_get_windows_version
failed (libglib-2.0.so) g_win32_locale_filename_from_utf8
failed (libgthread-2.0.so) g_mutex_new
failed (libgthread-2.0.so) g_mutex_lock
failed (libgthread-2.0.so) g_mutex_trylock
failed (libgthread-2.0.so) g_mutex_unlock
failed (libgthread-2.0.so) g_mutex_free
failed (libgthread-2.0.so) g_static_mutex_lock
failed (libgthread-2.0.so) g_static_mutex_trylock
failed (libgthread-2.0.so) g_static_mutex_unlock
failed (libgthread-2.0.so) g_static_mutex_get_mutex
failed (libgthread-2.0.so) g_cond_new
failed (libgthread-2.0.so) g_cond_signal
failed (libgthread-2.0.so) g_cond_broadcast
failed (libgthread-2.0.so) g_cond_wait
failed (libgthread-2.0.so) g_cond_timed_wait
failed (libgthread-2.0.so) g_cond_free
failed (libgthread-2.0.so) g_private_new
failed (libgthread-2.0.so) g_private_get
failed (libgthread-2.0.so) g_private_set
failed (libgthread-2.0.so) g_thread_supported
failed (libgthread-2.0.so) g_thread_create
failed (libgthread-2.0.so) g_thread_yield
failed (libpango-1.0.so) script_engine_list
failed (libpango-1.0.so) script_engine_init
failed (libpango-1.0.so) script_engine_exit
failed (libpango-1.0.so) script_engine_create
[New Thread 0x19fbb70 (LWP 2357)]
1 <= (length data received)
Received 1 bytes from 127.0.0.1:4444: d
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x19fbb70 (LWP 2357)]
0x00000000 in ?? ()
---------------------------------------------------------------------------
And info threads:
(gdb) info threads
* 2 Thread 0x19fbb70 (LWP 2357) 0x00000000 in ?? ()
1 Thread 0x116f90 (LWP 2353) 0x006e7416 in __kernel_vsyscall ()
---------------------------------------------------------------------------
I don't understand this, I hope it tells you something !
Thanks ! |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Tue Dec 08, 2009 3:13 pm Post subject: |
|
|
Thats the same output i get, i first thought it wan't correct.
But i found that the function pointers aren't set correctly by the loader.
This obviously resuts in a segfault when calling the function while is still null.
No clue as to why though. |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Tue Dec 08, 2009 3:37 pm Post subject: |
|
|
Mike Wey wrote: | No clue as to why though. |
TLS, the functions are only linked for one thread, the declerations for the fonction pointer probably need to be marked __gshared.
I've got threading working with this patch:
http://gtkd.mikewey.eu/shared.diff |
|
Back to top |
|
|
GG
Joined: 05 Nov 2009 Posts: 18
|
Posted: Tue Dec 08, 2009 7:44 pm Post subject: |
|
|
You got it Mike Wey !!!!!!!!!!!!!!!!!!!!!!!!!!!! It wasn't easy !!!
Thanks to confirm me that we can create threading application with D and GtkD. It's a real pleasure to work with.
Many thanks for this patch !
Only thing I have to do to make it work:
- after modifying files in gtkc/, don't forget to 'make clean' and 'make', at first time I forgot to clean and get :
-----------------------------------------
/usr/bin/ld: c_g_type_from_name: TLS reference in /usr/lib/gcc/i686-redhat-linux/4.4.2/../../../libgtkd.a(Builder.o) mismatches non-TLS definition in /usr/lib/gcc/i686-redhat-linux/4.4.2/../../../libgtkd.a(gobject.o) section .bss
/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../libgtkd.a: could not read symbols: Bad value
collect2: ld returned 1 exit status
-----------------------------------------
I know this code is not supposed to work under Windows but I'll try it just for fun.
Thanks Mike for your help. |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Wed Dec 09, 2009 4:04 pm Post subject: |
|
|
Now if only dmd1 also defined __gshared, than we could put it in svn as is. |
|
Back to top |
|
|
GG
Joined: 05 Nov 2009 Posts: 18
|
Posted: Wed Dec 09, 2009 6:06 pm Post subject: |
|
|
OK, good !
I compiled this code under Windows and ... it works !!!!! I'm surprised because it was not supposed... |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Thu Dec 10, 2009 12:52 pm Post subject: |
|
|
You can find the following in the gtk documentation:
Quote: | GLib is completely thread safe (all global data is automatically locked), but individual data structure instances are not automatically locked for performance reasons. So e.g. you must coordinate accesses to the same GHashTable from multiple threads.
GTK+ is thread aware but not thread safe it provides a global lock controlled by gdk_threads_enter()/gdk_threads_leave() which protects all use of GTK+. That is, only one thread can use GTK+ at any given time.
Unfortunately the above holds with the X11 backend only. With the Win32 backend, GDK calls should not be attempted from multiple threads at all.
You must call g_thread_init() and gdk_threads_init() before executing any other GTK+ or GDK functions in a threaded GTK+ program. |
http://library.gnome.org/devel/gdk/stable/gdk-Threads.html |
|
Back to top |
|
|
GG
Joined: 05 Nov 2009 Posts: 18
|
Posted: Thu Dec 10, 2009 1:47 pm Post subject: |
|
|
So, to create GUI application threading and work with progressbar for example, we can use :
- gdkThreadsEnter() with main gtk+ lock
- g_idle_add_full() in /Glib/Idle.d,
- or timeout in gtk/timeout.d
Right ? Is there a best choice ?
If the answer is YES, then I will try the idles and timeout.
Thanks ! |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Thu Dec 10, 2009 4:34 pm Post subject: |
|
|
I think glib.Idle would be a good choice.
If the function you're adding returns false, you could add the idle function every time you need to modify the progressbar. |
|
Back to top |
|
|
|