每次使用带有 LOCK_EX 标志的 LOCK_NB 时,相同的 program/process 获取锁
Same program/process acquiring lock every time when using LOCK_NB with LOCK_EX flag
我有一个要求,两个独立的 processes/programs 运行ning 并行(一个写在 Python 和一个写在 C++) 需要独占访问,修改一个硬件相关的值。
我正在尝试使用 flock 在它们之间实现同步。
同样的代码如下,
Python代码
#!/usr/bin/python
import fcntl
import time
import datetime
import os
SLICE_SLEEP = 5
LOCK_HOLD_TIME = 20
TOTAL_WAIT_TIME = 300
class LockUtil(object):
FILE_PATH = "/tmp/sync.lock"
fd = -1
@staticmethod
def acquireLock(totalWaitTime=TOTAL_WAIT_TIME):
try:
LockUtil.fd = os.open(LockUtil.FILE_PATH,os.O_WRONLY|os.O_CREAT)
print('Trying to acquire lock')
retryTimes = (totalWaitTime/SLICE_SLEEP)
currentCounter = 0
while currentCounter < retryTimes:
try:
fcntl.flock(LockUtil.fd,fcntl.LOCK_EX|fcntl.LOCK_NB)
print('Lock acquired successfully')
return
except IOError:
print('Failed to acquire the lock, sleeping for {} secs'.format(SLICE_SLEEP))
time.sleep(SLICE_SLEEP)
currentCounter += 1
print('Tried {} times, now returning'.format(retryTimes))
except IOError:
print('Can not access file at path: {}'.format(FILE_PATH))
@staticmethod
def releaseLock():
fcntl.flock(LockUtil.fd,fcntl.LOCK_UN)
print('Lock released successfully')
class LockHelper(object):
def __init__(self):
LockUtil.acquireLock()
def __del__(self):
LockUtil.releaseLock()
def createObjAndSleep():
lock = LockHelper()
time.sleep(LOCK_HOLD_TIME)
def main():
while True:
createObjAndSleep()
if __name__ == '__main__':
main()
C++ 代码
#include <iostream>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/file.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <ctime>
#include <memory>
int SLICE_SLEEP = 6;
int LOCK_HOLD_TIME = 20;
int TOTAL_WAIT_TIME = 300;
int SUCCESS = 0;
class LockUtil {
public:
static std::string path;
static int fd;
static int acquireLock(int totalWaitTime=TOTAL_WAIT_TIME);
static int releaseLock();
};
std::string LockUtil::path = "/tmp/sync.lock";
int LockUtil::fd = -1;
int LockUtil::acquireLock(int totalWaitTime) {
fd = open(path.c_str(), O_WRONLY|O_CREAT, 0666);
if(fd != -1)
{
auto retryTimes = (totalWaitTime/SLICE_SLEEP);
auto currentCounter = 0;
while(currentCounter < retryTimes)
{
std::cout << "Trying to acquire lock" << std::endl;
auto lockStatus = flock(fd,LOCK_EX|LOCK_NB);
if(lockStatus == SUCCESS)
{
std::cout << "Lock acquired successfully" << std::endl;
return 0;
} else {
std::cout << "Failed to acquire the lock, sleeping for " << SLICE_SLEEP << " secs" << std::endl;
sleep(SLICE_SLEEP);
currentCounter += 1;
}
}
} else {
std::cout << "Unable to open the file!" << std::endl;
std::cout << strerror(errno) << std::endl;
return -1;
}
}
int LockUtil::releaseLock() {
if(fd != -1)
{
flock(fd,LOCK_UN);
std::cout << "Lock released successfully" << std::endl;
return 0;
} else {
return -1;
}
}
class LockHelper {
public:
LockHelper() {
LockUtil::acquireLock();
}
~LockHelper() {
LockUtil::releaseLock();
}
};
void createObjAndSleep()
{
std::unique_ptr<LockHelper> lockObj(new LockHelper());
sleep(LOCK_HOLD_TIME);
}
int main(void) {
while (true) {
createObjAndSleep();
}
}
但是,当我 运行 这两个程序并行时,观察到第一个获得文件锁的进程一直在获取它,而另一个进程却饿死了。
但是,如果我将两个程序中的标志更改为仅使用 LOCK_EX 并删除 LOCK_NB, 锁以循环方式在进程之间共享。
我想了解使用LOCK_NB标志时程序中的错误是什么。
OS
uname -a
Linux 0000000000002203 4.4.43-hypriotos-v7+ #1 SMP PREEMPT Thu Jan 19 20:54:06 UTC 2017 armv7l GNU/Linux
Python 版本 - 2.7
C++ 版本 - C++11
我不认为这本身是一个错误,但可能是一个意外的结果。当您使用阻塞 flock
时,您的进程将被放入内部 Linux 内核队列,一旦锁被释放,它就会唤醒进程。
虽然 Linux flock 无法保证公平调度,但看起来事件序列或多或少地在公平调度中分配了锁定。
另一方面,使用非阻塞锁,您的进程会不断尝试锁定它。因此,没有锁队列,而是有进程在实时不断地竞争锁。为了获得这个锁,当锁可用时,进程需要处于 on-cpu 状态,而调度程序似乎此时不给进程机会。
调度策略非常复杂,所以我不会推测是什么导致了此调度程序行为。
最后但同样重要的是,您在非阻塞锁方面的最终目标是什么?你为什么要它们?
我有一个要求,两个独立的 processes/programs 运行ning 并行(一个写在 Python 和一个写在 C++) 需要独占访问,修改一个硬件相关的值。
我正在尝试使用 flock 在它们之间实现同步。
同样的代码如下,
Python代码
#!/usr/bin/python
import fcntl
import time
import datetime
import os
SLICE_SLEEP = 5
LOCK_HOLD_TIME = 20
TOTAL_WAIT_TIME = 300
class LockUtil(object):
FILE_PATH = "/tmp/sync.lock"
fd = -1
@staticmethod
def acquireLock(totalWaitTime=TOTAL_WAIT_TIME):
try:
LockUtil.fd = os.open(LockUtil.FILE_PATH,os.O_WRONLY|os.O_CREAT)
print('Trying to acquire lock')
retryTimes = (totalWaitTime/SLICE_SLEEP)
currentCounter = 0
while currentCounter < retryTimes:
try:
fcntl.flock(LockUtil.fd,fcntl.LOCK_EX|fcntl.LOCK_NB)
print('Lock acquired successfully')
return
except IOError:
print('Failed to acquire the lock, sleeping for {} secs'.format(SLICE_SLEEP))
time.sleep(SLICE_SLEEP)
currentCounter += 1
print('Tried {} times, now returning'.format(retryTimes))
except IOError:
print('Can not access file at path: {}'.format(FILE_PATH))
@staticmethod
def releaseLock():
fcntl.flock(LockUtil.fd,fcntl.LOCK_UN)
print('Lock released successfully')
class LockHelper(object):
def __init__(self):
LockUtil.acquireLock()
def __del__(self):
LockUtil.releaseLock()
def createObjAndSleep():
lock = LockHelper()
time.sleep(LOCK_HOLD_TIME)
def main():
while True:
createObjAndSleep()
if __name__ == '__main__':
main()
C++ 代码
#include <iostream>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/file.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <ctime>
#include <memory>
int SLICE_SLEEP = 6;
int LOCK_HOLD_TIME = 20;
int TOTAL_WAIT_TIME = 300;
int SUCCESS = 0;
class LockUtil {
public:
static std::string path;
static int fd;
static int acquireLock(int totalWaitTime=TOTAL_WAIT_TIME);
static int releaseLock();
};
std::string LockUtil::path = "/tmp/sync.lock";
int LockUtil::fd = -1;
int LockUtil::acquireLock(int totalWaitTime) {
fd = open(path.c_str(), O_WRONLY|O_CREAT, 0666);
if(fd != -1)
{
auto retryTimes = (totalWaitTime/SLICE_SLEEP);
auto currentCounter = 0;
while(currentCounter < retryTimes)
{
std::cout << "Trying to acquire lock" << std::endl;
auto lockStatus = flock(fd,LOCK_EX|LOCK_NB);
if(lockStatus == SUCCESS)
{
std::cout << "Lock acquired successfully" << std::endl;
return 0;
} else {
std::cout << "Failed to acquire the lock, sleeping for " << SLICE_SLEEP << " secs" << std::endl;
sleep(SLICE_SLEEP);
currentCounter += 1;
}
}
} else {
std::cout << "Unable to open the file!" << std::endl;
std::cout << strerror(errno) << std::endl;
return -1;
}
}
int LockUtil::releaseLock() {
if(fd != -1)
{
flock(fd,LOCK_UN);
std::cout << "Lock released successfully" << std::endl;
return 0;
} else {
return -1;
}
}
class LockHelper {
public:
LockHelper() {
LockUtil::acquireLock();
}
~LockHelper() {
LockUtil::releaseLock();
}
};
void createObjAndSleep()
{
std::unique_ptr<LockHelper> lockObj(new LockHelper());
sleep(LOCK_HOLD_TIME);
}
int main(void) {
while (true) {
createObjAndSleep();
}
}
但是,当我 运行 这两个程序并行时,观察到第一个获得文件锁的进程一直在获取它,而另一个进程却饿死了。
但是,如果我将两个程序中的标志更改为仅使用 LOCK_EX 并删除 LOCK_NB, 锁以循环方式在进程之间共享。
我想了解使用LOCK_NB标志时程序中的错误是什么。
OS
uname -a
Linux 0000000000002203 4.4.43-hypriotos-v7+ #1 SMP PREEMPT Thu Jan 19 20:54:06 UTC 2017 armv7l GNU/Linux
Python 版本 - 2.7
C++ 版本 - C++11
我不认为这本身是一个错误,但可能是一个意外的结果。当您使用阻塞 flock
时,您的进程将被放入内部 Linux 内核队列,一旦锁被释放,它就会唤醒进程。
虽然 Linux flock 无法保证公平调度,但看起来事件序列或多或少地在公平调度中分配了锁定。
另一方面,使用非阻塞锁,您的进程会不断尝试锁定它。因此,没有锁队列,而是有进程在实时不断地竞争锁。为了获得这个锁,当锁可用时,进程需要处于 on-cpu 状态,而调度程序似乎此时不给进程机会。
调度策略非常复杂,所以我不会推测是什么导致了此调度程序行为。
最后但同样重要的是,您在非阻塞锁方面的最终目标是什么?你为什么要它们?