[FFmpeg-trac] #1643(avcodec:new): Custom lock manager will cause multiple thread encoding deadlock

FFmpeg trac at avcodec.org
Wed Aug 15 15:37:01 CEST 2012


#1643: Custom lock manager will cause multiple thread encoding deadlock
----------------------------------+---------------------------------------
             Reporter:  chinshou  |                     Type:  defect
               Status:  new       |                 Priority:  normal
            Component:  avcodec   |                  Version:  unspecified
             Keywords:            |               Blocked By:
             Blocking:            |  Reproduced by developer:  0
Analyzed by developer:  0         |
----------------------------------+---------------------------------------
 I used av_lockmgr_register to register a custom mutex manager , then I am
 tring to convert a bitmap to jpeg. MJPEG encoder is multiple thread
 encoding capable encoder. After encoding finished, when I try to use
 avcodec_close to close the encoder , the program was deadlocked.

 I checked the source and found that to aovid thread safe problem, ffmpeg
 will call custom lock manager at the beginning of avcodec_close to assure
 exclusive access.

 av_cold int avcodec_close(AVCodecContext *avctx)
 {
     /* If there is a user-supplied mutex locking routine, call it. */
     if (ff_lockmgr_cb) {
         if ((*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN))
             return -1;
     }

 when multiple thread encoding , the main thread will call
 ff_frame_thread_encoder_free to close all the worker threads

         if (avctx->internal->frame_thread_encoder && avctx->thread_count >
 1) {
             entangled_thread_counter --;
             ff_frame_thread_encoder_free(avctx);
             entangled_thread_counter ++;
         }

 in the ff_frame_thread_encoder_free function , it set exit flag first ,
 then use pthread_join to wait all the worker thread to finish.

 when the worker threads found the exit flag and exit the loop , it will
 also call avcodec_close(avctx); to close their own codec
 .

 static void * attribute_align_arg worker(void *v){
 ...
     while(!c->exit){
 ...
         pthread_mutex_lock(&c->task_fifo_mutex);
         while (av_fifo_size(c->task_fifo) <= 0 || c->exit) {
             if(c->exit){
                 pthread_mutex_unlock(&c->task_fifo_mutex);
                 goto end;
             }
             pthread_cond_wait(&c->task_fifo_cond, &c->task_fifo_mutex);
         }
         av_fifo_generic_read(c->task_fifo, &task, sizeof(task), NULL);
         pthread_mutex_unlock(&c->task_fifo_mutex);
 ...
     }
 end:
     av_free(pkt);
     pthread_mutex_lock(&c->buffer_mutex);
     avcodec_close(avctx); <---
     pthread_mutex_unlock(&c->buffer_mutex);
     av_freep(&avctx);
     return NULL;
 }

  But the global ff_lockmgr_cb mutex already acquired by the main thread.
 so all the worker will be blocked  to wait the main thread to release the
 mutex, and the main thread is waiting all the worker threads , finally the
 program fall into deadlock.

 one possible solution is to add addition parameter to avcodec_close , when
 the flag was set , avcodec_close will not try to acquire the global custom
 mutex to avoid deadlock. All the internal worker thread should call the
 avcodec_close with this flag setted.

 I test it with 20120730 source so far.

 regards

-- 
Ticket URL: <https://ffmpeg.org/trac/ffmpeg/ticket/1643>
FFmpeg <http://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list