2

I am implementing a thread safe function to create directory if it does not exist.

void create_directory(char *str){   
    pthread_mutex_lock(mutex);
    if (stat(str, &st) == -1) {
        mkdir(str, 0700);
    }
    pthread_mutex_unlock(mutex);
}

Thread_1:

create_directory("dir1");

Thread_2:

create_directory("dir1");

Thread_3:

create_directory("dir2");


Thread_1 and Thread_2 are trying to create same directory, and and code works as expected. Problem is when Thread_3 tries to create another directory, i.e. "dir2", which has got nothing to do with directory "dir1", then Thread_3 is also get blocked.

What I want is to have lock on a directory instead of lock on a code section. How can I achieve this.

Or is there any other way to implement thread safe function to create directory. Or is there any function in C to do this.

V.d
  • 31
  • 6
  • 1
    What if another process creates the directory between `stat` and `mkdir`? – too honest for this site May 12 '17 at 06:30
  • 1
    Note that there's a TOCTOU (time of check, time of use) problem in using `stat` and then `mkdir`. Also note that `stat()` can fail for other reasons than ENOENT, and `stat()` can succeed even though the name is not a directory. See also [Creating a directory tree](http://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux/675193#675193) and [Checking if a directory exists](http://stackoverflow.com/questions/3828192/checking-if-a-directory-exists-in-unix-system-call/3828537#3828537). – Jonathan Leffler May 12 '17 at 06:41
  • you are right, TOCTOU problem may arise. Since I was creating directories in the program's dedicated directory, I was not expecting any other process to create the same directory. And also, all threads of my process uses this function to create directory. – V.d May 12 '17 at 12:19

3 Answers3

4

Why not just create the directory and if that returns an EEXIST error just ignore it. The end result is the same: you call your function and when it returns there is a directory.

It's an idempotent operation so there's no need to mess around with complex locking schemes. Especially since they will do nothing to prevent a different process from creating the same directory.

Art
  • 19,807
  • 1
  • 34
  • 60
1

You can hash your string to say 4 bits. Which will give you 16 possible options. Create an array of 16 mutexes and acquire lock only on the one that is your hash value. Collisions can still happen, but will be less.

You can increase your hash width to 8 bits for lesser collision but you would need more mutex objects.

Other approach is not to acquire lock on the costly part that is call to mkdir (it calls a system call).

But maintain a list of the directories being created at the moment. Every thread that tries to create a directory, first checks if that name is already in the list. If yes, it waits.

If not, it enters inserts the name and starts creating the directory. After it is done, it removes the name from the list.

Only the part of adding to the list and check will have to be protected by a simple lock and the operation will happen very quickly. So other threads operating on other directories wont have to wait as much.

Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49
0

If you want to have a lock on a directory then simply call mkdir and let the OS do its work.