Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

Domains: forum.doom9.org / forum.doom9.net / forum.doom9.se

 

Go Back   Doom9's Forum > Capturing and Editing Video > VapourSynth

Reply
 
Thread Tools Search this Thread Display Modes
Old 16th December 2025, 12:47   #1  |  Link
vcmohan
Registered User
 
Join Date: Jul 2003
Location: India
Posts: 913
Global lock for fftwf

I understand that all functions of fftwf dll excepting execute are not thread safe and so need to introduce global guard. avisynth+ has introduced an env-> function that facilitates this. When I google c++ about the Guard lock and mutex it mentioned that these are old and execution takes time. It recommends heap functions. I need help in coding as I do not have that expertise. Also vapourSynth may provide a mechanism for this purpose.
__________________
mohan
my plugins are now hosted here
vcmohan is offline   Reply With Quote
Old 16th December 2025, 23:49   #2  |  Link
LoRd_MuldeR
Software Developer
 
LoRd_MuldeR's Avatar
 
Join Date: Jun 2005
Location: Last House on Slunk Street
Posts: 13,275
Quote:
Originally Posted by vcmohan View Post
When I google c++ about the Guard lock and mutex it mentioned that these are old and execution takes time. It recommends heap functions.
Not sure what you mean. Cleary, if each thread allocates its own separate buffer on the heap, so that no buffer actually needs to be shared between multiple threads, then no synchronization (e.g. mutex) will be needed.

But, for as long as you do have shared buffers, and if threads may need to modify the buffer contents, then proper synchronization is required!

The standard synchronization primitive to protect (serialize) access to a shared buffer is a mutex. In C++, this is implemented by the std::mutex class. Furthermore, the C++ (RAII) way to lock/unlock a mutex is std::lock_guard.


Now, the FFTW documentation is pretty clear, that all functions, except for fftw_execute(), are not thread-safe and therefore do need explicit synchronization, if you want to access them for different threads:
Quote:
The upshot is that the only thread-safe routine in FFTW is fftw_execute (and the new-array variants thereof). All other routines (e.g. the planner) should only be called from one thread at a time. So, for example, you can wrap a semaphore lock around any calls to the planner; even more simply, you can just create all of your plans from one thread.

https://www.fftw.org/fftw3_doc/Thread-safety.html

You can not change how FFTW works internally, or that most of its functions are not thread-safe. So, there is no way around proper synchronization, in a multi-threaded application.

The general pattern would be as follows:
Code:
std::mutex g_mutex; // <-- global mutex that must be used (locked) by any thread that wants to call some FFTW function, except for fftw_execute()

void my_thread_safe_wrapper_function()
{
    // Locks the mutex here
    std::lock_guard<std::mutex> guard(g_mutex);

    // Now we can safely call the FFTW function that is *not* thread-safe
    fftw_whatever();

    // Mutex is automatically unlocked when `guard` goes out of scope
}

Of course, this will only work properly if every call to any of the "problematic" FFTW functions from any thread is protected (synchronized) by such a wrapper function.
__________________
Go to https://standforukraine.com/ to find legitimate Ukrainian Charities 🇺🇦✊

Last edited by LoRd_MuldeR; 17th December 2025 at 00:08.
LoRd_MuldeR is offline   Reply With Quote
Old 17th December 2025, 13:18   #3  |  Link
vcmohan
Registered User
 
Join Date: Jul 2003
Location: India
Posts: 913
Many thanks @LoRd_Mulder. I will try. In avisynth+ there is a globl lock code for version 12 and legacy mutex code for earlier versions. for ver 12 IScriptEnvironment pointer env provides a way for global lock. But earlier versions do not. I am therefore confused about the locking process. If you have time can you look into it?
__________________
mohan
my plugins are now hosted here
vcmohan is offline   Reply With Quote
Old 19th December 2025, 14:25   #4  |  Link
Julek
Registered User
 
Julek's Avatar
 
Join Date: Dec 2020
Posts: 100
Yu can:
1. use mutex inside getFrame.
2. allocate needed temp buff for each thread: https://github.com/HomeOfVapourSynth....cpp#L335-L393
3. use fmUnordered (vsapi->createVideoFilter): https://www.vapoursynth.com/doc/api/...m-vsfiltermode
__________________
CPU: AMD 3700X | GPU: RTX 3070Ti | RAM: 32GB 3200MHz
GitHub
Julek is offline   Reply With Quote
Old 19th December 2025, 17:27   #5  |  Link
LoRd_MuldeR
Software Developer
 
LoRd_MuldeR's Avatar
 
Join Date: Jun 2005
Location: Last House on Slunk Street
Posts: 13,275
Looking at the example plugin code here:
https://github.com/vapoursynth/vapou...ter_skeleton.c

The function VapourSynthPluginInit2() will be called once per plug-in DLL, whereas the function filterCreate() will be called once for each filter instance that is created.

To my understanding, filterCreate() could be called multiple times in parallel, e.g., if multiple instances of the filter are created:
https://www.vapoursynth.com/doc/apir...e.html#plugins

Consequently, even inside your filterCreate() function, you would have to synchronize every access to any FFTW function! (except for fftw_execute(), but this one probably is not used in filterCreate() anyway)

Meanwhile, I would assume that your filterGetFrame() function will only need to use one FFTW function, which is fftw_execute(). If that holds true, then no synchronization is needed there.

In other words, you create all your FFTW plans once in your filterCreate() function, which must be properly synchronized, but in your actual filterGetFrame() function you just use (via fftw_execute()) the plans that you have already created, so no further synchronization is needed. And, since filterCreate() only happens very rarely (once per instance), you probably do not need to worry about the "performance" of the synchronization primitive (e.g mutex)

________

Now, which mutex should you use to synchronize on?

At the very least, you need to create a single "global" mutex in your plugin DLL, which will be used (locked) by all the filter instances that are created – probably needed only inside the filterCreate() function.

But, of course, this will not help, if some other plugin DLL may also call into the FFTW library
__________________
Go to https://standforukraine.com/ to find legitimate Ukrainian Charities 🇺🇦✊

Last edited by LoRd_MuldeR; 19th December 2025 at 17:48.
LoRd_MuldeR is offline   Reply With Quote
Old 19th December 2025, 22:40   #6  |  Link
Z2697
Registered User
 
Join Date: Aug 2024
Location: Between my two ears
Posts: 959
I think vcmohan is looking for a lock that works across multiple fftw depending plugins. The avs+ function he mentioned is exactly for that purpose.
Z2697 is offline   Reply With Quote
Old 20th December 2025, 06:51   #7  |  Link
StvG
Registered User
 
Join Date: Jul 2018
Posts: 594
Next time, provide more context so others can understand the problem better - https://github.com/AviSynth/AviSynthPlus/issues/444
StvG is offline   Reply With Quote
Old 20th December 2025, 12:56   #8  |  Link
vcmohan
Registered User
 
Join Date: Jul 2003
Location: India
Posts: 913
Quote:
Originally Posted by LoRd_MuldeR View Post
Looking at the example plugin code here:
https://github.com/vapoursynth/vapou...ter_skeleton.c

you create all your FFTW plans once in your filterCreate() function, which must be properly synchronized, but in your actual filterGetFrame() function you just use (via fftw_execute()) the plans that you have already created, so no further synchronization is needed. And, since filterCreate() only happens very rarely (once per instance), you probably do not need to worry about the "performance" of the synchronization primitive (e.g mutex)

________

Now, which mutex should you use to synchronize on?

...............

But, of course, this will not help, if some other plugin DLL may also call into the FFTW library
Thanks. In my vcm plugin there are several function which use fftwf dll. Now in each of these functions I will use the mutex lock on fftwf_mallock ,fftwf_plan and other fftwf calls while in the init of creating the filter. In the frame I do not use any lock as I only use fftwf_execute calls.

But in the script one can include in the process two or more such functions.
Worried whether I will have any interference between functions. May be I should restrict fftwf to single thread only?
__________________
mohan
my plugins are now hosted here
vcmohan is offline   Reply With Quote
Old 20th December 2025, 16:03   #9  |  Link
yuygfgg
Registered User
 
Join Date: Oct 2024
Posts: 20
Quote:
Originally Posted by vcmohan View Post
Thanks. In my vcm plugin there are several function which use fftwf dll. Now in each of these functions I will use the mutex lock on fftwf_mallock ,fftwf_plan and other fftwf calls while in the init of creating the filter. In the frame I do not use any lock as I only use fftwf_execute calls.

But in the script one can include in the process two or more such functions.
Worried whether I will have any interference between functions. May be I should restrict fftwf to single thread only?
I think you will need a global mutex, and all functions should use that to lock their resources. For example, llvmexpr uses exactly the same technique to manage its jit cache. https://github.com/Sunflower-Dolls/V...vm/Jit.hpp#L66

When all functions (and multiple instances in the script) are called, they are all accessing the same global mutex variable in memory. Therefore, even if different threads run them simultaneously, they will wait for each other.

Last edited by yuygfgg; 20th December 2025 at 16:11.
yuygfgg is offline   Reply With Quote
Old 21st December 2025, 12:49   #10  |  Link
vcmohan
Registered User
 
Join Date: Jul 2003
Location: India
Posts: 913
Many thanks @YUYgfgg. In the script its possible that some user may call one function from my plugin that uses mutex for fftwf and another function from a different plugin also using fftwf . The mutexes can be different unless vapourSynth itself provides that global mutex and insists developers to use it for fftwf dll usage. Is my understanding correct?
__________________
mohan
my plugins are now hosted here
vcmohan is offline   Reply With Quote
Old 21st December 2025, 16:48   #11  |  Link
LoRd_MuldeR
Software Developer
 
LoRd_MuldeR's Avatar
 
Join Date: Jun 2005
Location: Last House on Slunk Street
Posts: 13,275
Quote:
Originally Posted by vcmohan View Post
Many thanks @YUYgfgg. In the script its possible that some user may call one function from my plugin that uses mutex for fftwf and another function from a different plugin also using fftwf . The mutexes can be different unless vapourSynth itself provides that global mutex and insists developers to use it for fftwf dll usage. Is my understanding correct?
Yeah, if your plugin defines its own "global" mutex, then this can be used to synchronize all concurrent actions (e.g. calls to FFTW functions) within your plugin, but it will not synchronize with other plugins at all.

In other words, other plugins don't have a clue about "your" mutex, and they may call into FFTW independently whenever they want

If you synchronize on a mutex that is provided by VapourSynth, then this may work to synchronize with other plugins - but only if all the other plugins happen to synchronize all of their relevant actions (e.g. calls to FFTW functions) on that very same mutex. I don't know if there is some sort of "best practice" that says that all VapourSynth plugins should be doing this. But, in general, you must not make any assumptions about what other plugins might do (or not).
__________________
Go to https://standforukraine.com/ to find legitimate Ukrainian Charities 🇺🇦✊

Last edited by LoRd_MuldeR; 21st December 2025 at 16:55.
LoRd_MuldeR is offline   Reply With Quote
Old 21st December 2025, 18:57   #12  |  Link
Myrsloik
Professional Code Monkey
 
Myrsloik's Avatar
 
Join Date: Jun 2003
Location: Kinnarps Chair
Posts: 2,647
What you more or less have to do here is keep your own copy of the fftw library loaded so you can guard things with your own global mutex. Either by simply using static linking or if you use dynamic linking by renaming the dll to a distinct name no one else uses.

Not all solutions are elegant.
__________________
VapourSynth - proving that scripting languages and video processing isn't dead yet
Myrsloik is offline   Reply With Quote
Old 22nd December 2025, 12:45   #13  |  Link
vcmohan
Registered User
 
Join Date: Jul 2003
Location: India
Posts: 913
Thanks for explaining and suggestions, if I keep FFTW dlls in my own folder and remove from windows system dll folders, then at runtime it will not work for others as I do dynamic linking. I will define my global mutex as static so that it will ensure that all functionn that plugin run without interfering with each other, In documenttation I will put a cautionary note. If vapourSynth provides a specific mutex for fftw dll then it solves most of the problems.
__________________
mohan
my plugins are now hosted here
vcmohan is offline   Reply With Quote
Old 22nd December 2025, 15:39   #14  |  Link
Myrsloik
Professional Code Monkey
 
Myrsloik's Avatar
 
Join Date: Jun 2003
Location: Kinnarps Chair
Posts: 2,647
Quote:
Originally Posted by vcmohan View Post
Thanks for explaining and suggestions, if I keep FFTW dlls in my own folder and remove from windows system dll folders, then at runtime it will not work for others as I do dynamic linking. I will define my global mutex as static so that it will ensure that all functionn that plugin run without interfering with each other, In documenttation I will put a cautionary note. If vapourSynth provides a specific mutex for fftw dll then it solves most of the problems.
The DLLs MUST HAVE A UNIQUE FILENAME. In windows if you load a DLL with the same filename a second time (path irrelevant) it will simply increment the reference count of the already loaded DLL and return a handle to the already loaded copy.

It's a fun quirk you rarely encounter but you have to know about to make this work.
__________________
VapourSynth - proving that scripting languages and video processing isn't dead yet
Myrsloik is offline   Reply With Quote
Old 22nd December 2025, 21:43   #15  |  Link
Adub
Fighting spam with a fish
 
Adub's Avatar
 
Join Date: Sep 2005
Posts: 2,754
It would seem that recent versions of FFTW3 may have a solution to this problem: https://www.fftw.org/fftw3_doc/Thread-safety.html

Quote:
Neither strategy works, however, in the following situation. The “application” is structured as a set of “plugins” which are unaware of each other, and for whatever reason the “plugins” cannot coordinate on grabbing the lock. (This is not a technical problem, but an organizational one. The “plugins” are written by independent agents, and from the perspective of each plugin’s author, each plugin is using FFTW correctly from a single thread.) To cope with this situation, starting from FFTW-3.3.5, FFTW supports an API to make the planner thread-safe:

void fftw_make_planner_thread_safe(void);
Adub is offline   Reply With Quote
Old 23rd December 2025, 12:59   #16  |  Link
vcmohan
Registered User
 
Join Date: Jul 2003
Location: India
Posts: 913
Many thanks @Adub. I will check it. fftw still prefers buffer creation through its malloc. There are other functions of fftw which are also used. All these need to be thread safe. Request @LoRd_MuldeR and @Myrslok also to look into this.
__________________
mohan
my plugins are now hosted here
vcmohan is offline   Reply With Quote
Old 23rd December 2025, 21:16   #17  |  Link
Myrsloik
Professional Code Monkey
 
Myrsloik's Avatar
 
Join Date: Jun 2003
Location: Kinnarps Chair
Posts: 2,647
Quote:
Originally Posted by vcmohan View Post
Many thanks @Adub. I will check it. fftw still prefers buffer creation through its malloc. There are other functions of fftw which are also used. All these need to be thread safe. Request @LoRd_MuldeR and @Myrslok also to look into this.
Why do you need me to read the documentation? std::mutex is your friend.

Quote:
The upshot is that the only thread-safe routine in FFTW is fftw_execute (and the new-array variants thereof). All other routines (e.g. the planner) should only be called from one thread at a time. So, for example, you can wrap a semaphore lock around any calls to the planner; even more simply, you can just create all of your plans from one thread.
You have std::aligned_alloc for allocations in C++17 if you use a modern compiler which you should. Or just use a mutex for the fftw ones. It's not like it'll bottleneck anything anyway.
__________________
VapourSynth - proving that scripting languages and video processing isn't dead yet
Myrsloik is offline   Reply With Quote
Reply

Tags
c++, fftwf, global lock

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 19:35.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2026, vBulletin Solutions Inc.