I want create lot of unique named files in my multi-thread (openmp) Fortran program, both for write and read, the work flow is that fortran creates a file, write some codes into it, then call an external program, which will generate an output file, and fortran will read this output file.
There was a post by Steve Lionel:
character(255) filename call generate_temp_name('TMP', filename) print *, trim(filename) contains subroutine generate_temp_name (prefix, outname) implicit none character(*), intent(in) :: prefix character(*), intent(out) :: outname real mrand integer irand logical ex logical, save :: init = .false. ! Initialize random number generator if (.not. init) then call random_seed init = .true. end if do ! Get a random number call random_number(mrand) ! Get the low 24 bits irand = transfer(mrand, irand) irand = iand(irand,Z'FFFFFF') write (outname,101) trim(prefix),irand 101 format (A,Z6.6,'.tmp') inquire (file=trim(outname),exist=ex) if (.not.ex) exit end do ! We have a name that does not exist (at least right now) return end subroutine generate_temp_name end
which was based on random numbers, I am not sure whether it is thread safe, or there may be other better solutions, such as call the system `mkstemp` (don't how to call it from fortran)
Two potential issues that I see:
1) the outname must be in storage local to the thread calling the subroutine. For example: a) On stack of the parallel region of the caller, allocated by .AND. descriptor on stack of the parallel region of the caller, c) in threadlocal storage.
2) While the file doesn't exist at the point of the inquire on line 32, the code does not protect against multiple threads performing the inquire on the same name before any one of them performs the OPEN.
I suggest you use something like this
integer, save :: fileSequenceNumber = 0 integer :: my_fileSequenceNumber ... !$omp critical(critical_generate_temp_name) my_fileSequenceNumber = fileSequenceNumber fileSequenceNumber = fileSequenceNumber + 1 !$omp end critical(critical_generate_temp_name) ...
You may want to modify this such that the starting fileSequenceNumber is initialize at program start to avoid conflicts with prior run created files.
You can also obtain the thread ID (call pthread_self()) and name mangle that with the fileSequenceNumber. You still would have old filenames laying around to deal with, but this would reduce the frequency of name collisions as well as avoid two threads from creating a same name file (within a program run).