Hướng dẫn python flock timeout - đàn trăn hết giờ

Tôi đang sử dụng Python 2.7

Tôi muốn tạo một hàm trình bao quanh fcntl.flock () sẽ hết thời gian chờ sau một khoảng thời gian đã đặt:

wrapper_function(timeout):

Tôi đã thử gọi vào một chủ đề khác và sử dụng luồng.join (hết thời gian) nhưng có vẻ như fcntl.flock () tiếp tục chặn:

def GetLock(self, timeout):
    """Returns true if lock is aquired, false if lock is already in use"""
    self.__lock_file = open('proc_lock', 'w')

    def GetLockOrTimeOut():
        print 'ProcessLock: Acquiring Lock'            
        fcntl.flock(self.__lock_file.fileno(), fcntl.LOCK_EX)
        print 'ProcessLock: Lock Acquired'

    thread = threading.Thread(target=GetLockOrTimeOut)
    thread.start()
    thread.join(timeout)

    if thread.isAlive():
        print 'GetLock timed out'
        return False
    else:
        return True

Tôi đã xem xét các giải pháp để chấm dứt các luồng, giải pháp phổ biến nhất dường như là phân lớp phụ. Chủ đề và thêm một tính năng để nêu ra một ngoại lệ trong luồng. Tuy nhiên, tôi đã bắt gặp một liên kết nói rằng phương thức này sẽ không hoạt động với các cuộc gọi gốc, điều mà tôi khá chắc chắn fcntl.flock () đang gọi một hàm gốc. Đề xuất?

Bối cảnh: Tôi đang sử dụng khóa tệp để tạo một ứng dụng thể hiện duy nhất nhưng tôi không muốn một phiên bản thứ hai của ứng dụng ngồi xung quanh và treo cho đến khi kết thúc phiên bản đầu tiên.

Đã hỏi ngày 10 tháng 3 năm 2011 lúc 3:45Mar 10, 2011 at 3:45

Hướng dẫn python flock timeout - đàn trăn hết giờ

Thời gian chờ cho các cuộc gọi hệ thống được thực hiện với tín hiệu. Hầu hết các cuộc gọi hệ thống chặn trở lại với EINTR khi tín hiệu xảy ra, do đó bạn có thể sử dụng alarm để thực hiện thời gian chờ.

Đây là một người quản lý bối cảnh làm việc với hầu hết các cuộc gọi hệ thống, khiến Ioerror được nâng lên từ một cuộc gọi hệ thống chặn nếu mất quá nhiều thời gian.

import signal, errno
from contextlib import contextmanager
import fcntl

@contextmanager
def timeout(seconds):
    def timeout_handler(signum, frame):
        pass

    original_handler = signal.signal(signal.SIGALRM, timeout_handler)

    try:
        signal.alarm(seconds)
        yield
    finally:
        signal.alarm(0)
        signal.signal(signal.SIGALRM, original_handler)

with timeout(1):
    f = open("test.lck", "w")
    try:
        fcntl.flock(f.fileno(), fcntl.LOCK_EX)
    except IOError, e:
        if e.errno != errno.EINTR:
            raise e
        print "Lock timed out"

Đã trả lời ngày 10 tháng 3 năm 2011 lúc 4:30Mar 10, 2011 at 4:30

Glenn Maynardglenn MaynardGlenn Maynard

54.4K10 Huy hiệu vàng117 Huy hiệu bạc131 Huy hiệu đồng10 gold badges117 silver badges131 bronze badges

4

Tôi chắc chắn có một số cách, nhưng làm thế nào về việc sử dụng khóa không chặn? Sau một số n cố gắng, từ bỏ và thoát?

Để sử dụng khóa không chặn, bao gồm cờ fcntl.LOCK_NB, như trong:

fcntl.flock(self.__lock_file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)

Hướng dẫn python flock timeout - đàn trăn hết giờ

Congusbongus

12.6K6 Huy hiệu vàng69 Huy hiệu bạc95 Huy hiệu Đồng6 gold badges69 silver badges95 bronze badges

Đã trả lời ngày 10 tháng 3 năm 2011 lúc 3:50Mar 10, 2011 at 3:50

jcomeau_ictxjcomeau_ictxjcomeau_ictx

37K6 Huy hiệu vàng92 Huy hiệu bạc103 Huy hiệu Đồng6 gold badges92 silver badges103 bronze badges

7

Đối với Python 3.5+, giải pháp của Glenn Maynard không còn hoạt động vì PEP-475. Đây là phiên bản sửa đổi:

import signal, errno
from contextlib import contextmanager
import fcntl

@contextmanager
def timeout(seconds):
    def timeout_handler(signum, frame):
        # Now that flock retries automatically when interrupted, we need
        # an exception to stop it
        # This exception will propagate on the main thread, make sure you're calling flock there
        raise InterruptedError

    original_handler = signal.signal(signal.SIGALRM, timeout_handler)

    try:
        signal.alarm(seconds)
        yield
    finally:
        signal.alarm(0)
        signal.signal(signal.SIGALRM, original_handler)

with timeout(1):
    f = open("test.lck", "w")
    try:
        fcntl.flock(f.fileno(), fcntl.LOCK_EX)
    except InterruptedError:
        # Catch the exception raised by the handler
        # If we weren't raising an exception, flock would automatically retry on signals
        print("Lock timed out")

Đã trả lời ngày 14 tháng 7 năm 2019 lúc 2:33Jul 14, 2019 at 2:33

remramremramremram

4.5271 Huy hiệu vàng 30 Huy hiệu bạc42 Huy hiệu Đồng1 gold badge30 silver badges42 bronze badges

3

Tôi là một fan hâm mộ của việc bắn tung nên đổ xô ở đây, vì việc cố gắng thực hiện khóa chặn với thời gian chờ đòi hỏi phải thay đổi trạng thái toàn cầu, điều này khiến cho việc lý luận khó khăn hơn về chương trình của bạn, đặc biệt là nếu có liên quan đến luồng.

Bạn có thể loại bỏ một quy trình con và thực hiện báo thức như trên, hoặc bạn chỉ có thể thực hiện http://man7.org/linux/man-pages/man1/flock.1.html

import subprocess
def flock_with_timeout(fd, timeout, shared=True):
    rc = subprocess.call(['flock', '--shared' if shared else '--exclusive', '--timeout', str(timeout), str(fd)])
    if rc != 0:
        raise Exception('Failed to take lock')

Nếu bạn có một phiên bản mới của đàn bạn, bạn có thể sử dụng -E để chỉ định một mã thoát khác cho lệnh khác, nhưng không thực hiện được khóa sau khi hết thời gian, vì vậy bạn có thể biết liệu lệnh có thất bại vì lý do khác không.

Đã trả lời ngày 15 tháng 9 năm 2015 lúc 7:32Sep 15, 2015 at 7:32

Hướng dẫn python flock timeout - đàn trăn hết giờ

2

Như một bổ sung cho @Richard MAW Trả lời ở trên https://stackoverflow.com/a/32580233/17454091 (không có đủ danh tiếng để đăng bình luận).

Trong Python 3.2 và mới hơn, để FDS có sẵn trong các quy trình phụ, người ta cũng phải cung cấp đối số

def GetLock(self, timeout):
    """Returns true if lock is aquired, false if lock is already in use"""
    self.__lock_file = open('proc_lock', 'w')

    def GetLockOrTimeOut():
        print 'ProcessLock: Acquiring Lock'            
        fcntl.flock(self.__lock_file.fileno(), fcntl.LOCK_EX)
        print 'ProcessLock: Lock Acquired'

    thread = threading.Thread(target=GetLockOrTimeOut)
    thread.start()
    thread.join(timeout)

    if thread.isAlive():
        print 'GetLock timed out'
        return False
    else:
        return True
0.

Giải pháp hoàn chỉnh kết thúc như:

import subprocess
def flock_with_timeout(fd, timeout, shared=True):
    rc = subprocess.call(['flock',
                          '--shared' if shared else '--exclusive',
                          '--timeout', str(timeout),
                          str(fd)],
                         pass_fds=[fd])
    if rc != 0:
        raise Exception('Failed to take lock')

Đã trả lời ngày 20 tháng 12 năm 2021 lúc 15:38Dec 20, 2021 at 15:38