当我开发用于为每个数据库添加书签信息的注册表系统(c / c ++,2.6.32-642.6.2.el6.x86_64#1 SMP)时,会出现这个问题,这需要锁定内部和内部处理。通常,lockf(),flock(),fcntl()是进程间锁定的明显候选者,但后来我发现它们不能按预期进行进程内锁定(同一个多线程)处理)。
我使用以下程序对其进行了测试:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <fcntl.h> /* For O_RDWR */
#include <unistd.h> /* For open(), creat() */
#include <errno.h>
int counter = 0;
void* counterThread(void* ptr)
{
int lockfd = 0;
int tmpCounter = 0;
lockfd = open("/tmp/lockfile.txt", O_CREAT|O_WRONLY, 0666);
if(lockfd == -1)
{
printf("lockfile could not be created, errno:%d\n", errno);
return NULL;
}
if(lockf(lockfd, F_LOCK, 0) == -1)
{
printf("lockfile could not be locked, errno:%d\n", errno);
return NULL;
}
counter++;
tmpCounter = counter;
if(lockf(lockfd, F_ULOCK, 0) == -1)
{
printf("lockfile could not be unlocked, errno:%d\n", errno);
return NULL;
}
close(lockfd);
printf("counter is %d, lockfile is %d\n", tmpCounter, lockfd);
}
int main()
{
int threadNum = 30000;
pthread_t threads[30000];
int i = 0;
int rv = 0;
for(; i < threadNum; i++)
{
rv = pthread_create( &threads[i], NULL, &counterThread, NULL);
if(rv != 0)
{
printf("failed to create pthread %d\n", i);
return -1;
}
}
for(i = 0; i < threadNum; i++)
pthread_join(threads[i], NULL);
return 0;
}
输出结果为:
counter is 1, lockfile is 4
counter is 2, lockfile is 3
counter is 3, lockfile is 5
counter is 4, lockfile is 6
counter is 7, lockfile is 4
...
counter is 29994, lockfile is 3
counter is 29995, lockfile is 3
counter is 29996, lockfile is 3
counter is 29997, lockfile is 3
counter is 29998, lockfile is 3
输出序列是随机的,有时会遗漏一些数字,这意味着确实存在竞争条件。我认为原因可能是在同一进程中为同一个文件打开的fd以某种方式进行了优化以便重用。因为所有这些锁定机制都是以fd的粒度实现的,所以在这种情况下锁定不起作用。
鉴于背景,我想问下列问题:
在Linux中是否有任何良好实践或方便的API来进行内部和内部进程锁定?我能想到的是以下实现它的方法(尚未验证),但我想知道一些更简单的方法:
(1)实现互斥和信号量以序列化对关键资源的所有这些lockfile API的访问
(2)shm_open共享内存,在不同进程中对其进行mmap,并在内部添加信号量/互斥锁以锁定关键资源
提前致谢:)