我曾经以为flock(2)是线程安全的,但最近在代码中遇到一种情况,多个线程可以对同一文件获取锁,这些锁都是使用c api flock获取的。 进程25554是一个具有20个线程的多线程应用程序,当死锁发生时,持有同一文件锁的线程数量会有所变化。多线程应用程序testEvent将写入文件,而推入则从文件读取内容。不幸的是,lsof
不打印LWP值,因此我无法找到持有锁的线程。 当下面提到的条件发生时,进程和线程都会在flock调用上卡住,如pid 25569和25554上的pstack
或strace
调用所显示的那样。你有什么建议可以在RHEL 4.x中克服这个问题吗?
我想更新的一件事是,flock并非每次都表现不良,只有当消息的传输速率超过2 mbps时,才会出现这种死锁问题,在低于该速率的情况下一切正常。我保持了num_threads
= 20,size_of_msg
= 1000字节的常量,只是变化了每秒传输的消息数,从10条消息开始到100条消息,即20 * 1000 * 100 = 2 mbps,当我将消息数量增加到150时,就会出现flock问题。
我想问一下您对flockfile c api的看法。
sudo lsof filename.txt
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
push 25569 root 11u REG 253.4 1079 49266853 filename.txt
testEvent 25554 root 27uW REG 253.4 1079 49266853 filename.txt
testEvent 25554 root 28uW REG 253.4 1079 49266853 filename.txt
testEvent 25554 root 29uW REG 253.4 1079 49266853 filename.txt
testEvent 25554 root 30uW REG 253.4 1079 49266853 filename.txt
多线程测试程序将调用 write_data_lib_func
库函数。
void* sendMessage(void *arg) {
int* numOfMessagesPerSecond = (int*) arg;
std::cout <<" Executing p thread id " << pthread_self() << std::endl;
while(!terminateTest) {
Record *er1 = Record::create();
er1.setDate("some data");
for(int i = 0 ; i <=*numOfMessagesPerSecond ; i++){
ec = _write_data_lib_func(*er1);
if( ec != SUCCESS) {
std::cout << "write was not successful" << std::endl;
}
}
delete er1;
sleep(1);
}
return NULL;
上述方法将在测试主函数中的pthreads中被调用。
for (i=0; i<_numThreads ; ++i) {
rc = pthread_create(&threads[i], NULL, sendMessage, (void *)&_num_msgs);
assert(0 == rc);
}
以下是写入者/读取者的源代码,由于保密原因我不想直接剪切粘贴,写入者源代码将会在进程中被多个线程访问。
int write_data_lib_func(Record * rec) {
if(fd == -1 ) {
fd = open(fn,O_RDWR| O_CREAT | O_APPEND, 0666);
}
if ( fd >= 0 ) {
/* some code */
if( flock(fd, LOCK_EX) < 0 ) {
print "some error message";
}
else {
if( maxfilesize) {
off_t len = lseek ( fd,0,SEEK_END);
...
...
ftruncate( fd,0);
...
lseek(fd,0,SEEK_SET);
} /* end of max spool size */
if( writev(fd,rec) < 0 ) {
print "some error message" ;
}
if(flock(fd,LOCK_UN) < 0 ) {
print some error message;
}
在读取器方面,存在一个没有线程的守护进程。
int readData() {
while(true) {
if( fd == -1 ) {
fd= open (filename,O_RDWR);
}
if( flock (fd, LOCK_EX) < 0 ) {
print "some error message";
break;
}
if( n = read(fd,readBuf,readBufSize)) < 0 ) {
print "some error message" ;
break;
}
if( off < n ) {
if ( off <= 0 && n > 0 ) {
corrupt_file = true;
}
if ( lseek(fd, off-n, SEEK_CUR) < 0 ) {
print "some error message";
}
if( corrupt_spool ) {
if (ftruncate(fd,0) < 0 ) {
print "some error message";
break;
}
}
}
if( flock(fd, LOCK_UN) < 0 )
print some error message ;
}
}
}
flock
的代码吗?最好附上一个 简单的 测试程序。 - phihag