#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;
}

I want that every clone() will wait for lock. But Output of this code (something like this):

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 :

But when i am removing CLONE_FILES field set from clone(2), it goes all well. Other clone threads will wait for a lock().

Output of that:

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

Any other alternatives (with CLONE_FILES)? And Why this kind of behavior?

Beginner in this field.

有帮助吗?

解决方案

The locking provided by flock is per process, not per thread.

From http://linux.die.net/man/2/flock (emphasis mine):

A call to flock() may block if an incompatible lock is held by another process.

Subsequent flock() calls on an already locked file will convert an existing lock to the new lock mode.

Locks created by flock() are associated with an open file table entry.

Although threads are not explicitly mentioned multiple threads share a file table entry whereas multiple processes do not. Passing CLONE_FILES to clone causes your 'processes' to share file tables.

A solution might be to call dup to make more file descriptors. From the documentation:

If a process uses open(2) (or similar) to obtain more than one descriptor for the same
file, these descriptors are treated independently by flock(). An attempt to lock the file using one of these file descriptors may be denied by a lock that the calling process has already placed via another descriptor.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top