0

我正在创建一个使用mplayer. 我试图让它工作的方式是允许多个线程(通过 HTTP 请求)可以播放一首歌曲。但是,我不想同时播放多首歌曲,也不想排队。我只想播放最近的请求。不过,我的互斥体有问题。当我期望它时,它并不总是返回锁定状态。

Class Handler

    def initialize
        @read_io, @write_io = IO.pipe
        @child = nil
        @mutex = Mutex.new
    end

    def play_song_with_id(id)
        if @mutex.locked? then # this doesn't always return as expected
            stop_mplayer # this is how I interupt the child
            @mutex.unlock
        end
        if @mutex.lock then
            @child = fork do
                STDIN.reopen(@read_io)
                `mplayer -really-quiet "#{id}"`
                exit
            end
            Process.detatch(@child)
        end
    end

    def stop_mplayer() 
        @write_io.write "q" # mplayer takes input 'q' to quit
    end

end

只是为了给出完整的画面,这就是我路由请求的方式。一个简单的WEBrick服务器:

if $0 == __FILE__ then

    # Create the server
    server = WEBrick::HTTPServer.new(:Port=>port)
    ip = IPSocket.getaddress(Socket.gethostname)

    # Create a handler
    handler = Handler.new

    # Define routes
    server.mount "/handle", Routes::HandleRoute, handler

    # Handle interuptions
    trap "INT" do
        server.shutdown
    end

    # Start the server
    puts "\n===================="
    puts " * Server running at #{ip} on port #{port}"
    puts "====================\n\n"

    server.start
end

和路线:

class HandleRoute < WEBrick::HTTPServlet::AbstractServlet

    def initialize server, handler
        @handler = handler
    end

    def do_POST(request, response)
        if(request.body)
            @handler.play_song_with_id(request.body)
        end
    end

end

TL;DR - 不知何故,有时会同时播放两首歌曲,我想用它@mutex来防止这种情况。我想播放最近的请求,并停止当前正在进行的任何播放。我想知道我试图停止播放的方式是问题,而不是互斥体?如果是这样,打断孩子的更好方法是什么?

4

2 回答 2

2

我会尝试简化您对互斥锁的使用。您当前的实现看起来容易受到互斥锁解锁和再次锁定之间的时间问题的影响。

class Handler
  def play_song_with_id(id)
    @mutex.synchronize do
        stop_mplayer
        @child = fork do
            STDIN.reopen(@read_io)
            `mplayer -really-quiet "#{id}"`
            exit
        end
        Process.detach(@child)
    end
  end
end
于 2013-10-11T12:26:30.810 回答
0

在这种情况下,我认为您真的不需要互斥锁。由于您只想播放最新的,因此每当完成新请求时,您总是可以终止 mplayer。所以:

def play_song_with_id(id)
  stop_mplayer_if_any
  start_mplayer
end


def stop_mplayer_if_any() 
  @write_io.write "q"
rescue => e # Please do a better job here, rescuing only the really expected exceptions
  logger.info "Rescuing from #{e.inspect} and ignoring"
end

def start_mplayer
  @child = fork do
    STDIN.reopen(@read_io)
    `mplayer -really-quiet "#{id}"`
    exit
  end
end

并且在不需要时不会出现同步问题。

于 2013-10-11T21:50:05.473 回答