- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have searched the sample folders to find an example of how to arrange a program to run the run the number crunching in a separate thread, but with no results. Can anyone advice how to build a Win32 multithreaded program in Fortran?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
>>to run the run the number crunching in a separate thread
Can you describe your application a bit better than this. What you stated seems to imply you intend to have one thread number crunching, and a different thread doing something else. What is this something else?
If you are using Microsoft Visual Studio:
In the Solution Explorer window, right-click on your project | Properties | Configuration Properties | Fortran | Language | Process OpenMP Directives | Generate Parallel Code (/Qopenmp)
If you are compiling from the command line or Makefile, add the /Qopenmp option
This informs the compiler to incorporate parallelism per directives inserted into your program. Your program must have these directives inserted into the program.
From your description, which is atypical of most parallel programs you get:
program SomethingElse use omp_lib ! required module for interfaces to OpenMP library routines implicit none ! Variables real :: X ! Body of SomethingElse X = 0.0 !$OMP PARALLEL SECTIONS CALL CRUNCH() !$OMP SECTION CALL OTHER() !$OMP END PARALLEL SECTIONS PAUSE "Done with Parallel Sections" end program SomethingElse subroutine Crunch() USE IFPORT print *, "Begin crunch" CALL SLEEPQQ(10) ! Your number crunching code would be here print *,"end Crunch" ! Sleep is used to simulate your compute time end subroutine crunch subroutine Other() character(100) :: text print *, 'Enter your name:' read (*,*) text print *, "Hello ", text end subroutine Other
A more typical program parallelizes the compute section
program SomethingElse use omp_lib ! required module for interfaces to OpenMP library routines implicit none ! Variables integer, parameter :: N=50000 real, allocatable :: X(:,:) real :: SumOfSquares real(8) :: T integer :: I, J ! Body of SomethingElse T = omp_get_wtime() allocate(X(N,N)) print *, "Time to allocate:", omp_get_wtime() - T T = omp_get_wtime() X = 1.001 ! Whatever your data is... print *, "Time to initialize:", omp_get_wtime() - T ! Serial version of code T = omp_get_wtime() SumOfSquares = 0.0 DO J=1,N DO I=1,N SumOfSquares = SumOfSquares + X(I,J)**2 END DO END DO print *,"Time to compute serially:", omp_get_wtime() - T, SumOfSquares T = omp_get_wtime() !$OMP PARALLEL I = 0 ! do approximately no work !$OMP END PARALLEL print *,"Time to initialize thread team:", omp_get_wtime() - T ! parallel version T = omp_get_wtime() SumOfSquares = 0.0 !$OMP PARALLEL DO REDUCTION(+:SumOfSquares) DO J=1,N DO I=1,N SumOfSquares = SumOfSquares + X(I,J)**2 END DO END DO !$OMP END PARALLEL DO print *,"Time to compute in parallel:", omp_get_wtime() - T, SumOfSquares end program SomethingElse
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The program is a MDI application named "TVA" that is simulating torque response in a power train (shaft) system, either in the frequency or in the time domain. The program has also inbuilt functions (dialogues) to display the calculated results in different windows and to manipulate the input data files in text windows. Especially the time-domain simulation may be rather time-consuming, the PC is frozen for 30 minutes +/- dependent on the model size. If I run other applications (send an e-mail) the "spinning wheel" appears and TVA tends to terminate.
I am thinking that running the Runge Kutta integrations in a separate thread would solve the problem. However, it should be mentioned that these bad things never happened with Win XP and VS2005/IVF...Currently I am using Win 8 with VS2013 and XE2013Sp1.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You could try simply adding the /parallel option (Optimization > Parallel > Yes) and see what that gets you. The compiler will analyze loops to see if any are worth parallelizing. This is typically not as effective as Jim's suggestion of using OpenMP but it may get you better performance. Use of higher optimization levels, whole-program optimization and use of advanced instruction sets will also help.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In programs like what you described, use CreateThread to launch a separate thread, and then have that thread call a Modal Dialog Box to do the displays and/or manipulate control buttons and gages. Then do the bulk computation from OpenMP parallel regions run by the main thread. The control code for your dialog box(es) would plop values into, and extract values from, globally shared variables (module data variables or COMMON variable data).
An alternative is to I launch one or more modeless dialog boxes.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jim, the main thread is not the main message loop I guess. Otherwise there is no main thread, all events are initiated from dialogues.The computation is launched by a subroutine call from the callback routine to modeless dialogue box, see text below. This subroutine makes calls to other routines and data is exchanged by data modules, common blocks and subroutine calls..... .
if (LoWord(wParam) == IDC_RUN) the
iret = GetDlgItemText(hDlg, IDC_Filut, text, 40)
text = text(1:index(text,char(0))-1) ! C-string to Fortran string
read(text,'(A)') FileNameOut ! read back name of output files
call FDTVc45(IDUM,rc,hprogress1,ISTAT) ! CALCULATION
Steve, I will check your proposal !
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In your #6 post, the subroutine FDTVc45 can be compiled with !$OMP directives for parallelization. However, the call will block the dialog until the call finishes. If, on the other hand, you want to launch the subroutine on a separate thread, then immediately return such that the dialog box (that launched the thread) can display progress information, then you will need to use CreateThread to spawn a thread that makes the call to FDTVc45 (pass the arguments as a pointer to a user defined type or in module stored data).
The alternative, which I tend to use, is to launch a console application the is intended to perform the computation. This (main) thread then launches a modeless dialog box, then the compute thread waits for instructions from the dialog box (via periodic polling of shared variables).
if (LoWord(wParam) == IDC_RUN) then iret = GetDlgItemText(hDlg, IDC_Filut, text, 40) text = text(1:index(text,char(0))-1) ! C-string to Fortran string read(text,'(A)') FileNameOut ! read back name of output files FDTVc45args%IDUM = IDUM FDTVc45args%rc = rc FDTVc45args%progress = hprogress1 FDTVc45args%ISTAT = YourBusyStatusValue ! e.g. 123456789 FDTVc45args%Run = .true. ! thread will shortly see Run then take off endif ! Here your dialog continues to run doing other things
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In my case, the computation takes hours or days to complete. I want the controlling dialog box to continue running, displaying progress information. Using my #7 suggestion, hprogress1 can be a handle on the dialog box that informs the other thread to run FDTVc45. In your #6 case, where the computation is run on the same thread as the dialog, hprogress1 needs to be on a different dialog box (that is running), else if on same dialog box, you will not see progress updates during run. You will only see the final progress state.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There is an alternative, that I haven't tried, I suggest you give it a try as it will simplify things greatly if it works
PROGRAM YourCurrentProgram
use omp_lib
... ! your current data declarations
! First program statements
!$OMP PARALLEL
!$OMP MASTER
! your YourCurrentProgram contents (sans END PROGRAM)
...
!$OMP END MASTER
!$OMP END PARALLEL
END PROGRAM YourCurrentProgram
... in your dialog code
if (LoWord(wParam) == IDC_RUN) then
iret = GetDlgItemText(hDlg, IDC_Filut, text, 40)
text = text(1:index(text,char(0))-1) ! C-string to Fortran string
read(text,'(A)') FileNameOut ! read back name of output files
!$OMP TASK
call FDTVc45(IDUM,rc,hprogress1,ISTAT) ! CALCULATION
!$OMP END TASK
! Here your dialog continues to run doing other things
endif
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Jim,
The program TVA is a Windows program that has a WinMain, a MainWndProc function and a MDIWnd Proc function as a "frame". All calculations and graphical output is processed by callback subroutines to modeless dialogues. In the call to FDTVC45, the argument "hprogress1" is the handle to the progress bar that is updated after each calculation step in in FDTVC45. So the progress bar shown in the dialogue, is updated by FDTVC45 (maybe a strange approach, but it tends to work if not the spinning wheel pops up, ref #1)
In your post #9 l above, would "PROGRAM YourCurrentProgram" be the callback routine?
Thinking about your post #7, I do not understand how a Win program can instruct a console program. But OK, FDTVC45 could be a program that was started by a "WinExec or Shellexecute call?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Nothing wrong with having a WinMain. However, you may need to call for_rtl_init_ at start of WinMain and for_rtl_finish_ at end of WinMain. (See User and Reference Guide)
You cannot have PROGRAM as callback.
RE #7
You would have a console program (with hidden or minimized window) that launches a separate thread using CreateThread, then that thread initializes and runs a Modal Dialog Box
returnVal = DlgModal( ControlPanelDlg )
A variation on this is to have WinMain call for_rtl_init_then use CreateThread to call a subroutine that has the contents of what was in PROGRAM scenario. That program has a loop using SLEEPQQ for short interval and which polls on action variables set by the control panel,
High Poppa Lowem, Low Poppa Highem (skin the bark off the tree either way)
If you do not like SLEEPQQ spinwaiting then incorporate WaitForSingleEvent.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I tried your proposal #9, however during link I get the message:
Error 9 error LNK2019: unresolved external symbol _FOR_RTL_INIT_@0 referenced in function _WinMain MAIN-TVA51-2016.obj
Error 10 error LNK2019: unresolved external symbol _FOR_RTL_FINISH_@0 referenced in function _WinMain MAIN-TVA51-2016.obj
Error 11 fatal error LNK1120: 2 unresolved externals Debug\TVA-2016-2.exe
I have added "use omp_lib at the top and before the main message loop call for_rtl_init_ but I am not able to find anything in the VS2013 documentation about this..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Those routine names are in lowercase and not STDCALL. I don't see any reference to them in Jim's post #9. You would not call these from Fortran code.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
The prototypes for the _for_rtl_... functions are not listed in the documentation nor findable using
Find all "for_rtl_", Match case, Subfolders, Find Results 2, "C:\Program Files (x86)\IntelSWTools", "*.c;*.cpp;*.cxx;*.cc;*.tli;*.tlh;*.h;*.hh;*.hpp;*.hxx;*.hh;*.inl;*.rc;*.resx;*.idl;*.asm;*.inc"
In searching the internet, I find different signatures for these functions. Can you post the correct way(s) to call these functions (and also add a note to update the documentation to include these).
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
They're in the index, Jim. Also https://software.intel.com/en-us/node/679292 and https://software.intel.com/en-us/node/679291 They've been documented for many years. I can't speak to the command you used, but my search tool found them easily.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page