Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Multithreaded application example

reidar
New User
2,735 Views

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?

0 Kudos
14 Replies
jimdempseyatthecove
Honored Contributor III
2,734 Views

>>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

0 Kudos
reidar
New User
2,734 Views

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.

 

0 Kudos
Steven_L_Intel1
Employee
2,734 Views

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.

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,734 Views

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

0 Kudos
reidar
New User
2,734 Views

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

 

 

 

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,734 Views

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

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,734 Views

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

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,734 Views

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
 

0 Kudos
reidar
New User
2,734 Views

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?

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,734 Views

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

0 Kudos
reidar
New User
2,734 Views

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..

 

0 Kudos
Steven_L_Intel1
Employee
2,734 Views

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.

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,734 Views

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 

0 Kudos
Steven_L_Intel1
Employee
2,734 Views

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.

Capture.PNG

0 Kudos
Reply