0

I have a bash script that may be run many times in parallel, and I need to be able to check the value in a file and modify it. Ideally, I'd like whichever script instance that gets there first to be able to do the reading and the writing without interference from another instance. I thought I could do this with flock, but it seems that some commands get ignored--I guess because they can't get a lock?

Here's what I have so far:

myfunc () {
    { flock -x 3 ; count=$(cat <&3); } 3< countfile
    { flock -x 3 ; echo $((count+1)) >&3; } 3> countfile
}

This is run from a subshell, so I have to do the counts via a file.

So, two things

  1. This is not using the same lock to read and write--I'd like that, but I'm not sure howto do it
  2. Why are my reads sometimes ignored?

Thanks!

donutbrew
  • 81
  • 1
  • 6
  • 1
    You probably can do what you want with `flock`, supposing that all processes agree to do it that way (since `flock` provides *discretionary* locking only). It's unclear how your problem actually manifests, however. You'll get better help if you provide a minimal, complete example with which we can reproduce your issue. – John Bollinger Nov 18 '15 at 21:30
  • Your existing code locks the file, reads it, unlocks it, locks it again, writes it, and unlocks it. That's manifestly unsafe, since it means **the file could have been changed by someone else between when the first lock is released and when the second lock takes place**. – Charles Duffy Nov 18 '15 at 22:34

2 Answers2

1

You don't need to reuse the same descriptor for both read and write processes. In other languages, this would be a code smell, but bash doesn't have native support for seeking within an existing FD, making it a matter of unfortunate necessity.

myfunc () {
  {
    flock -x 3 || return
    count=$(<countfile)
    echo "$((count + 1 ))" >countfile
  } 3<>countfile
}

That said -- not all solutions are native! @telotortium has written an excellent C helper which can be used to seek within a pre-opened FD; if you were to use their code to seek back to the beginning of the file (or something similar to truncate it to 0 and move the FD there), you could reuse a single file descriptor for both the read and the write.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
0

i followed the example here. I'm not entirely sure why switching to using variable stream descriptors helped, but I accomplished what I needed. The other thing that's different, is that in the example there they are using the actual filename inside the subshell where it is locked, rather than actually referring to the stream.

This is new stuff to me, so I welcome comments.

Community
  • 1
  • 1
donutbrew
  • 81
  • 1
  • 6
  • 1
    Could you show **exactly** how you followed that example? It's not completely obvious how it addressed your concerns, and thus whether the new code has the same problem (re: separate locks rather than a contiguous mutex) as what was given in the question. – Charles Duffy Nov 18 '15 at 22:40