Skip to main content
Added some in line comments and an explanation for the last example.
Source Link

#Sample task task(){ sleep 0.5; echo "$1"; }

#Sequential runs

for thing in a b c d e f g; do 
   task "$thing"
done

#Parallel runs for thing in a b c d e f g; do task "$thing" & done

#Parallel runs in N-process batches N=4 ( for thing in a b c d e f g; do ((i=i%N)); ((i++==0)) && wait task "$thing" & done )

It's also possible to use FIFOs as semaphores and use them to ensure that new processes are spawned as soon as possible and that no more than N processes runs at the same time. But it requires more code.

#N processes with a FIFO-based semaphore:

# initialize a semaphore with a given number of tokens
open_sem(){
    mkfifo pipe-$$
    exec 3<>pipe-$$
    rm pipe-$$
    local i=$1
    for((;i>0;i--)); do
        printf %s 000 >&3
    done
}

# run the given command asynchronously and pop/push tokens
run_with_lock(){
    local x
    # this read waits until there is something to read
    read -u 3 -n 3 x && ((0==x)) || exit $x
    (
     ( "$@"; )
    # push the return code of the command to the semaphore
    printf '%.3d' $? >&3
    )&
}

N=4
open_sem $N
for thing in {a..g}; do
    run_with_lock task $thing
done 

Explanation:

We use file descriptor 3 as a semaphore by pushing (=printf) and poping (=read) tokens ('000'). By pushing the return code of the executed tasks, we can abort if something went wrong.

#Sample task task(){ sleep 0.5; echo "$1"; }

#Sequential runs

for thing in a b c d e f g; do 
   task "$thing"
done

#Parallel runs for thing in a b c d e f g; do task "$thing" & done

#Parallel runs in N-process batches N=4 ( for thing in a b c d e f g; do ((i=i%N)); ((i++==0)) && wait task "$thing" & done )

It's also possible to use FIFOs as semaphores and use them to ensure that new processes are spawned as soon as possible and that no more than N processes runs at the same time. But it requires more code.

#N processes with a FIFO-based semaphore:

open_sem(){
    mkfifo pipe-$$
    exec 3<>pipe-$$
    rm pipe-$$
    local i=$1
    for((;i>0;i--)); do
        printf %s 000 >&3
    done
}
run_with_lock(){
    local x
    read -u 3 -n 3 x && ((0==x)) || exit $x
    (
     ( "$@"; )
    printf '%.3d' $? >&3
    )&
}

N=4
open_sem $N
for thing in {a..g}; do
    run_with_lock task $thing
done 

#Sample task task(){ sleep 0.5; echo "$1"; }

#Sequential runs

for thing in a b c d e f g; do 
   task "$thing"
done

#Parallel runs for thing in a b c d e f g; do task "$thing" & done

#Parallel runs in N-process batches N=4 ( for thing in a b c d e f g; do ((i=i%N)); ((i++==0)) && wait task "$thing" & done )

It's also possible to use FIFOs as semaphores and use them to ensure that new processes are spawned as soon as possible and that no more than N processes runs at the same time. But it requires more code.

#N processes with a FIFO-based semaphore:

# initialize a semaphore with a given number of tokens
open_sem(){
    mkfifo pipe-$$
    exec 3<>pipe-$$
    rm pipe-$$
    local i=$1
    for((;i>0;i--)); do
        printf %s 000 >&3
    done
}

# run the given command asynchronously and pop/push tokens
run_with_lock(){
    local x
    # this read waits until there is something to read
    read -u 3 -n 3 x && ((0==x)) || exit $x
    (
     ( "$@"; )
    # push the return code of the command to the semaphore
    printf '%.3d' $? >&3
    )&
}

N=4
open_sem $N
for thing in {a..g}; do
    run_with_lock task $thing
done 

Explanation:

We use file descriptor 3 as a semaphore by pushing (=printf) and poping (=read) tokens ('000'). By pushing the return code of the executed tasks, we can abort if something went wrong.

added 5 characters in body
Source Link
Petr Skocik
  • 29.7k
  • 18
  • 90
  • 155

#Sample task task(){ sleep 0.5; echo "$1"; }

#Sequential runs

for thing in a b c d e f g; do 
   task "$thing"
done

#Parallel runs for thing in a b c d e f g; do task "$thing" & done

#Parallel runs in N-process batches N=4 ( for thing in a b c d e f g; do ((i=i%N)); ((i++==0)) && wait task "$thing" & done )

It's also possible to use FIFOs as semaphores and use them to ensure that new processes are spawned as soon as possible and that no more than N processes runs at the same time. But it requires more code.

#N processes with a FIFO-based semaphore:

open_sem(){
    mkfifo pipe-$$
    exec 3<>pipe-$$
    rm pipe-$$
    local i=$1
    for((;i>0;i--)); do
        printf %s 000 >&3
    done
}
run_with_lock(){
    local x
    read -u 3 -n 3 x && ((0==x)) || exit $x
    (
    "$@" ( "$@"; )
    printf '%.3d' $? >&3
    )&
}

N=4
open_sem $N
for thing in {a..g}; do
    run_with_lock task $thing
done 

#Sample task task(){ sleep 0.5; echo "$1"; }

#Sequential runs

for thing in a b c d e f g; do 
   task "$thing"
done

#Parallel runs for thing in a b c d e f g; do task "$thing" & done

#Parallel runs in N-process batches N=4 ( for thing in a b c d e f g; do ((i=i%N)); ((i++==0)) && wait task "$thing" & done )

It's also possible to use FIFOs as semaphores and use them to ensure that new processes are spawned as soon as possible and that no more than N processes runs at the same time. But it requires more code.

#N processes with a FIFO-based semaphore:

open_sem(){
    mkfifo pipe-$$
    exec 3<>pipe-$$
    rm pipe-$$
    local i=$1
    for((;i>0;i--)); do
        printf %s 000 >&3
    done
}
run_with_lock(){
    local x
    read -u 3 -n 3 x && ((0==x)) || exit $x
    (
    "$@" 
    printf '%.3d' $? >&3
    )&
}

N=4
open_sem $N
for thing in {a..g}; do
    run_with_lock task $thing
done 

#Sample task task(){ sleep 0.5; echo "$1"; }

#Sequential runs

for thing in a b c d e f g; do 
   task "$thing"
done

#Parallel runs for thing in a b c d e f g; do task "$thing" & done

#Parallel runs in N-process batches N=4 ( for thing in a b c d e f g; do ((i=i%N)); ((i++==0)) && wait task "$thing" & done )

It's also possible to use FIFOs as semaphores and use them to ensure that new processes are spawned as soon as possible and that no more than N processes runs at the same time. But it requires more code.

#N processes with a FIFO-based semaphore:

open_sem(){
    mkfifo pipe-$$
    exec 3<>pipe-$$
    rm pipe-$$
    local i=$1
    for((;i>0;i--)); do
        printf %s 000 >&3
    done
}
run_with_lock(){
    local x
    read -u 3 -n 3 x && ((0==x)) || exit $x
    (
     ( "$@"; )
    printf '%.3d' $? >&3
    )&
}

N=4
open_sem $N
for thing in {a..g}; do
    run_with_lock task $thing
done 
added 710 characters in body
Source Link
Petr Skocik
  • 29.7k
  • 18
  • 90
  • 155

#Sample task task(){ sleep 0.5; echo "$1"; }

#Sequential runs

for thing in a b c d e f g; do 
   task "$thing"
done

#Parallel runs for thing in a b c d e f g; do task "$thing" & done

#Parallel runs in N-process batches N=4 ( for thing in a b c d e f g; do ((i=i%N)); ((i++==0)) && wait task "$thing" & done )

It's also possible to use FIFOs as semaphores and use them to ensure that new processes are spawned as soon as possible and that no more than N processes runs at the same time. But it requires more code.

#N processes with a FIFO-based semaphore:

open_sem(){
    mkfifo pipe-$$
    exec 3<>pipe-$$
    rm pipe-$$
    local i=$1
    for((;i>0;i--)); do
        printf %s 000 >&3
    done
}
run_with_lock(){
    local x
    read -u 3 -n 3 x && ((0==x)) || exit $x
    (
    "$@" 
    printf '%.3d' $? >&3
    )&
}

N=4
open_sem $N
for thing in {a..g}; do
    run_with_lock task $thing
done 

#Sample task task(){ sleep 0.5; echo "$1"; }

#Sequential runs

for thing in a b c d e f g; do 
   task "$thing"
done

#Parallel runs for thing in a b c d e f g; do task "$thing" & done

#Parallel runs in N-process batches N=4 ( for thing in a b c d e f g; do ((i=i%N)); ((i++==0)) && wait task "$thing" & done )

#Sample task task(){ sleep 0.5; echo "$1"; }

#Sequential runs

for thing in a b c d e f g; do 
   task "$thing"
done

#Parallel runs for thing in a b c d e f g; do task "$thing" & done

#Parallel runs in N-process batches N=4 ( for thing in a b c d e f g; do ((i=i%N)); ((i++==0)) && wait task "$thing" & done )

It's also possible to use FIFOs as semaphores and use them to ensure that new processes are spawned as soon as possible and that no more than N processes runs at the same time. But it requires more code.

#N processes with a FIFO-based semaphore:

open_sem(){
    mkfifo pipe-$$
    exec 3<>pipe-$$
    rm pipe-$$
    local i=$1
    for((;i>0;i--)); do
        printf %s 000 >&3
    done
}
run_with_lock(){
    local x
    read -u 3 -n 3 x && ((0==x)) || exit $x
    (
    "$@" 
    printf '%.3d' $? >&3
    )&
}

N=4
open_sem $N
for thing in {a..g}; do
    run_with_lock task $thing
done 
deleted 4 characters in body
Source Link
Petr Skocik
  • 29.7k
  • 18
  • 90
  • 155
Loading
Source Link
Petr Skocik
  • 29.7k
  • 18
  • 90
  • 155
Loading