Community
Participate
Working Groups
Run the attached test case. I tested it on a Sun JDK 1.2.2. Some notes: - the problem occures with both syncExec and asyncExec. - the problem even showed up on my system if both threads have the same priority (NORM_PRIORITY). I only changed to priority to make sure that the problem shows up. =================== Test Case ===================================== package com.oti.dbaeumer.swt.prs; import com.ibm.swt.*; import com.ibm.swt.events.*; import com.ibm.swt.layout.*; import com.ibm.swt.widgets.*; public class PR_1G03DF0 { Shell shell; Table table; Button button; public PR_1G03DF0() { } public PR_1G03DF0 close () { if ((shell != null) && (!shell.isDisposed ())) shell.dispose (); shell= null; table= null; return this; } public PR_1G03DF0 open () { shell = new Shell (); shell.setText ("Block Example"); shell.setSize (300, 200); shell.setLayout(new GridLayout()); table= new Table(shell, SWT.FULL_SELECTION | SWT.HIDE_SELECTION | SWT.BORDER); GridData gd= new GridData(); gd.horizontalAlignment= gd.FILL; gd.grabExcessHorizontalSpace= true; gd.verticalAlignment= gd.FILL; gd.grabExcessVerticalSpace= true; table.setLayoutData(gd); table.setHeaderVisible(true); table.setLinesVisible(true); TableColumn tc1= new TableColumn(table, SWT.NONE); tc1.setWidth(80); tc1.setText("Column 1"); TableColumn tc2= new TableColumn(table, SWT.NONE); tc2.setWidth(80); tc2.setText("Column 2"); for (int i= 0; i < 2; i++) { TableItem item= new TableItem(table, SWT.NONE); item.setText(0, "Item " + i); item.setText(1, "Item " + i); } table.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { System.out.println("Element selected"); } }); shell.open (); return this; } public PR_1G03DF0 run () { Display display = shell.getDisplay (); while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); } return this; } public static void main(java.lang.String[] args) { PR_1G03DF0 window= new PR_1G03DF0().open(); final Display display= window.shell.getDisplay(); // Only need to make sure the problem shows up. Thread.currentThread().setPriority(Thread.MIN_PRIORITY); Thread thread= new Thread(new Runnable() { public void run() { int counter= 0; do { // display.asyncExec(new Runnable() { display.syncExec(new Runnable() { public void run() { } }); counter++; if (counter == 10000) { System.out.println("10000 items produced"); counter= 0; } } while (true); } }, "Producer"); // Only need to make sure the problem shows up. thread.setPriority(Thread.MAX_PRIORITY); thread.start(); window.run().close(); } } NOTES: VI (8/28/00 4:10:21 PM) I have tried this example on Windows 98. With the priorities as set above, I get the behaviour that the table selection events are not getting processed but this is what I would expect to happen because the UI thread has been given such a low relative priority. When I changed the example so that both threads have the NORM_PRIORITY thread priority, the UI events get processed regularly. I tried this both under J9 and JDK 1.2.2. Is there something I am missing? DB (8/29/00 10:21:14 AM) I sometimes get the behavior on my machine even if I set the priority of both threads to NORM_PRIORITY. In general I have the following problem with the example from above: - I start a thread having a display. This thread processes UI events. Lets call the thread the UI thread. - I start a second thread that post runnable synchronously into the UI thread. Lets call the thread the producer thread. Now you get the following behavior: - the UI thread gets activated every time the producer thread post the runnable into the UI thread, because the runnable is posted using syncExec. At this point the producer thread waits until the runnable is executed. - the UI thread executes the event in the method runAsyncMessages(). So the UI thread is active. After the runnable is executed via the call "look.run()" the "synchronized (lock)" block is finished and a thread scheduling can occur (which is very probably since most VM schedule threads after a synchronized block of after a notifyAll() call). If the producer thread gets activated then it produces a new runnable and post it synchronously into the event queue. - This again activates the UI thread. Since it is still in the do-while(true) loop in runAsyncMessages it removes the first runnable form the message queue (and there is one since the produces thread has just created one) and executes the runnable. This produces the blocking of the native UI events since the runAsyncMessages method is never left. The problem that I have with this behaviour is, that 1.) although there are native events created long before the runnables have been posted into the event queue, and 2.) I guarantee the activation of the UI thread by using syncExec the native UI events from the native event queue get never "worked off" because the UI thread never leaves the runAsyncMessages method. In my opinion that should not happen even if the UI thread runs on LOW_PRIORITY. Using asyncExec instead of syncExec doesn't change anything in general. If I use asyncExec the event thread gets activated from time to time and should also check in runAsyncMessages if there are new native UI events which wait for processing. SN (2/5/01 2:46:40 PM) No further action. We were unable to get the code to fail. DB (06.02.2001 12:19:33) This is still an open issue in Eclipse and it seems that VI was able to reproduce the problem. McQ (26/06/2001 10:37:38 AM) - VI claims that she was *unable* to reproduce the problem. SSQ should read this to see if he understands what's going on.
PRODUCT VERSION: SWT 0.45.
Dirk, we fixed a bug recently where repeately asyncExec'ing caused the UI thread to block. What this what you were seeing? Can we close this PR? It seems that when you set the thread priority low for the UI thread, the UI becomes unresponsive but this is expected.
The problem still exists. The code has been moved to a new class but still has the same characteristics. If a thread produces more runnables and post them to the UI thread using async or sync exec than the UI thread can process, then the do {....} while(true) loop in Synchronizer is never left and therefore no native events are processed. I created a smaller example that demonstrates this. It is attached to the PR. Run it and try to press the button or the shell's close box. Nothing happens. Clicking on the close box several times opens a dialog saying that the application is not responding to user events.
Created attachment 1728 [details] Example code
Fixed > 20020731. Note that then old example code hangs Windows 98 because the UI thread exits and the producer thread keeps going, adding work to the queue which is no longer getting taken off. Here is new DB example code that does not hang Windows 98 and works: import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; public class PR_4521 { Shell shell; Button button; public PR_4521() { } public PR_4521 close () { if ((shell != null) && (!shell.isDisposed ())) shell.dispose (); shell= null; return this; } public PR_4521 open () { shell = new Shell (); shell.setText ("Block Example"); shell.setSize (300, 200); shell.setLayout(new GridLayout()); button= new Button(shell, SWT.PUSH); button.setText("Press Me"); button.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { System.out.println("Button pressed"); } public void widgetDefaultSelected(SelectionEvent e) { } }); shell.open (); return this; } public PR_4521 run () { Display display = shell.getDisplay (); while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); } return this; } public static void main(java.lang.String[] args) { PR_4521 window= new PR_4521().open(); final Display display= window.shell.getDisplay(); final Shell shell = window.shell; Thread producer= new Thread(new Runnable() { public void run() { do { if (shell.isDisposed()) break; display.asyncExec(new Runnable() { public void run() { try { Thread.currentThread().sleep(10); } catch (InterruptedException e) { } } }); } while (true); } }, "Producer"); producer.start(); window.run().close(); } }