[FFmpeg-devel] Network IO in FFmpeg (was: abstractable threading api)

Roger Pack rogerdpack2 at gmail.com
Fri Dec 20 20:24:36 CET 2013


On 12/19/13, Nicolas George <george at nsup.org> wrote:
> Le sextidi 26 frimaire, an CCXXII, Hendrik Leppkes a écrit :
>> The compat isn't complete, it just contains the functions needed by
>> avcodec et al, well short of pthread_cancel.
>> However, providing pthread_cancel with win32 threading api is also
>> non-trivial, if not impossible to find a "drop in" compat
>> functionality.
>>
>> Canceling threads from the outside is a no-no in the win32 API. Most
>> blocking functions usually have the option to give it a unblock event
>> that you can trigger to release it, and safely shut down the thread
>> from within, however as you can imagine thats not something that ports
>> well over different APIs.
>>
>> The best course of action in this case would probably be to find a way
>> to re-write this worker thread without pthread_cancel, other solutions
>> seem rather ugly.
>
> Regarding the pthread_cancel thing, I am the one responsible for this bit
> of
> code, I can explain how it is needed.
>
> The basic idea is that we have a thread blocked inside a system call:
>
> 	read(udp_sock_fd, buffer, size);
>
> and we want to terminate it, because reading on the socket is finished.
> Note
> that no packet may arrive there for a long time, so waiting for the system
> call to return by itself is not an option.
>
> First, a small discussion: in this particular case, we want to stop the
> whole thread. If we had a way of interrupting just the system call,
> stopping
> the thread is just a matter of checking a flag afterwards. If the situation
> were inverted: we knew how to cancel the thread but want to interrupt just
> the system call, then we could start a new thread just for the system call:
> more work, but that does the trick. In short: whether we cancel the system
> call or the whole thread, we are good.
>
> Now, let us see the options:
>
> * Signals
>
>   Using a signal to interrupt a system call is a long tradition, but
>   handling signals reliably is a portability nightmare, and mixing threads
>   with signals is that squared. Let us avoid it.
>
> * pthread_cancel()
>
>   With true POSIX threads, it is perfect: pthread_cancel() only interrupts
>   at specific points of the code, so we do not need to care about
> atomicity,
>   and reading on a socket is guaranteed to be one.

Yeah, unfortunately I'm not even sure if win32-pthreads is able to
emulate this (though it says it does) without relying on 3rd party
QueueUserAPCEx library which feels a bit violent...

> * Closing the socket
>
>   ... does not work.

Do you have an example where this doesn't work?  For fun I tried this
(ruby) code:
https://gist.github.com/rdp/8058776
on OS X, windows, and Linux and (at least with ruby 1.8.x) closing the
socket seemed to work ok.  However, this may have been because at
first glance it seems to do a select before doing the actual recv...

I think this one is the reason that today's code works in windows with
a crippled win32-pthreads (it closes the socket, allowing the thread
to terminate).  Though I suppose you might want to mutex the closings
so you don't accidentally double close (the second close could
accidentally close a newly opened socket on the same fd number).)

Anyway the good news here is that it works today on windows as is,
because AFAICT it's using the "closing the socket to interrupt the
thread" trick, FWIW.

> * Non-blocking I/O + usleep() + retry loop / poll() with periodic timeout
>
>   The "poll() with periodic timeout" solution was used before I changed it
> to
>   pthread_cancel(). Both solution work, but they are universally frowned
>   upon.

(I assume poll() is the equivalent of using select in windows?)
The disadvantage to this and the reason it is frowned upon is because
it requires a timeout worth of time to cancel the thread?

> * poll() + self-pipe
>
>   The idea is to poll() on both the socket and a pipe internal to the
>   program. Writing on the internal pipe allows to interrupt the poll() call
>   immediately.

This would seem to overcome the problem of the timeout (if it's
possible to write it portably--in windows I've seen people use a UDP
socket for this purpose before [1] or maybe a TCP socket would work?).

So I guess my order of preference would be "closing the socket" (or
using current pthread cancel code, which happens to do this) then
"poll+self-pipe"

Cheers.
-roger-
[1] https://github.com/eventmachine/eventmachine/blob/master/ext/em.cpp#L318


More information about the ffmpeg-devel mailing list