1
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define __USE_GNU
#include <sched.h>

void init_lock(struct flock *f)
{
    f->l_type = F_WRLCK;      /* write lock set */
    f->l_whence = SEEK_SET;
    f->l_start = 0;
    f->l_len = 0;
    f->l_pid = getpid();
}

int lock(int fd, struct flock *f)
{
    init_lock(f);
    if(fcntl(fd, F_SETLKW, f) == -1) {
        fprintf(stderr,"fcntl() failed: %s\n", strerror(errno));
        return -1;
    }
    return 0;
}

int unlock(int fd, struct flock *f)
{
f->l_type = F_UNLCK;
if(fcntl(fd, F_SETLK, f) == -1) {
    fprintf(stderr, "fcntl() failed: %s\n", strerror(errno));
    return -1;
}
return 0;
}

int file_op(void *arg)
{
char buff[256];
int fd = (int) arg, n;
struct flock my_lock;

printf("Trying to get lock\n");
if(lock(fd, &my_lock) == -1) {    /* lock acquired by a thread */
    return -1;
}

printf("Got lock: %d\n", getpid());  /* I am printing thread id after lock() */
printf("Enter string to write in file : ");
scanf("%s", buff);

if((n=write(fd, &buff, strlen(buff))) == -1) {
    fprintf(stderr, "write() failed: %s\n", strerror(errno));
}

if(unlock(fd, &my_lock) == -1) {
    return -1;
}
printf("Lock Released: %d\n", getpid());
return 0;
}

int main()
{
char *stack;
int fd, i=0, cid, stacksize;

if((fd = open("sample.txt", O_CREAT | O_WRONLY | O_APPEND, 0644)) == -1) {
    printf("Error in file opening\n");
    exit(1);
}

stacksize = 3*1024*1024;
for(i=0; i<5; i++) {
    stack = malloc(stacksize);
    if((cid = clone(&file_op, stack + stacksize, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD, (void *) fd)) == -1) {
        fprintf(stderr,"clone() failed: %s\n", strerror(errno));
        break;
    }
}
sleep(30);
close(fd);
return 0;
}

すべてのclone()がロックを待つようにしたい。しかし、このコードの出力(このようなもの):

Trying to get lock
Trying to get lock
Trying to get lock
Got lock: Got lock: 10287
Got lock: Got lock: 10287

Enter string to write in file : Trying to get lock
Enter string to wriGot lock: 10287
Got lock: 10287
Got lock: 10287
Enter string to write in file : Trying to get lock
Got lock: 10287
Got lock: Enter string to write in file :

しかし、clone(2)からCLONE_FILESフィールドセットを削除すると、すべてうまくいきます。他のクローンスレッドはlock()を待ちます。

その出力:

Trying to get lock
Got lock: 10311
Trying to get lock
Trying to get lock
Trying to get lock
Trying to get lock

他の選択肢(CLONE_FILESを使用)はありますか?そして、なぜこの種の行動なのか?

この分野の初心者。

4

1 に答える 1

2

によって提供されるロックはflock、スレッドごとではなく、プロセスごとです。

http://linux.die.net/man/2/flock(私の強調)から:

互換性のないロックが別のプロセスによって保持されている場合、flock()の呼び出しがブロックされることがあります。

すでにロックされているファイルに対する後続のflock()呼び出しは、既存のロックを新しいロックモードに変換します。

flock()によって作成されたロックは、開いているファイルテーブルエントリに関連付けられています。

スレッドは明示的に言及されていませんが、複数のスレッドはファイルテーブルエントリを共有しますが、複数のプロセスは共有しません。に渡すCLONE_FILESclone、「プロセス」がファイルテーブルを共有します。

dup解決策は、より多くのファイル記述子を作成するために呼び出すことかもしれません。ドキュメントから:

プロセスがopen(2)(または同様のもの)を使用して同じ
ファイルに対して複数の記述子を取得する場合、これらの記述子はflock()によって個別に処理されます。これらのファイル記述子の1つを使用してファイルをロックしようとすると、呼び出し元のプロセスが別の記述子を介してすでに設定しているロックによって拒否される場合があります。

于 2012-08-30T13:25:41.267 に答える