How do I get an error in a try catch to end all running tasks

In the code below when the first task throws an error I want it to kill the second task immediately and then go to the catch block. I think the code currently ends the first task and then just runs the second task, and if it finished it would then go to the catch block.

try 
    @sync begin
        @async throw(ArgumentError)
        @async while true
            sleep(2)
            println("oops")
        end
    end
catch err
    println("Caught")
end

This code also exhibits the similar behaviour, where it does immediately go to the catch block but the while loop doesn’t end

try 
    @sync begin
        @async while true
            sleep(2)
            println("oops")
        end
        throw(ArgumentError)
    end
catch err
    println("Caught")
end

What do I need to do to get the desired behaviour of all tasks stopping when an error is thrown?

These two solutions work for me. It seems it is easiest to end a task if you are waiting on some x
in the task for which you can call close(x) when you have an error, which closes the task waiting on x. That’s why we use Timer here.

try 
    @sync let timer
        @async begin
            timer = Timer(2) do _
                println("oops")
            end
        end

        try
            @sync begin
                @async throw(ArgumentError)
            end
        catch err
            println("Caught 1")
            close(timer)
            rethrow()
        end
    end
catch err
    println("Caught")
end
try 
    @sync let timer
        @async begin
            timer = Timer(2) do _
                println("oops")
            end
        end

        try
            throw(ArgumentError)
        catch err
            println("Caught 1")
            close(timer)
            rethrow()
        end
    end
catch err
    println("Caught")
end