Let\'s say that I have a procedure called myproc. This is a complex process and i cannot allow two instances executing at the same time the proc.>
You can create a table processes. You also ensure that each process has some sort of unique identifier - for instance a hash of the owner, object_name from dba_objects so you could create this dynamically in your package.
You then create a function to lock each row individually as a process is run.
As @Sergio pointed out in the comments this would not work if for some reason you needed to commit in the middle of the process - unless, of course, you re-selected after each commit.
function locking ( Pid ) return number is
l_locked number := 0;
begin
select 1
into l_locked
from processes
where id = Pid
-- exit immediately if the proc is running
for update nowait
;
return l_locked;
exception when others then
return 0;
end;
This has the benefit of locking that row in processes for you until the session that's currently running your procedure has finished.
You then wrap this in your procedure:
-- if we failed to lock locking will have thrown an error
-- i.e. we have 0 here.
if locking( 123 ) = 0 then
exit;
end if;
As long as each procedure has a unique id - the important bit - your procedure will exit cleanly.
It might not apply in your situation but, my normal way of doing this is to use mod. Though it doesn't stop 2 of the same process running it does ensure that when you have more than 1 you only run them on different data. Something like as follows:
procedure my_procedure ( PNumerator number, PDenominator number ) is
cursor c_my_cursor ( CNumerator number, CDenominator number ) is
select columns
from my_table
where mod( ascii(substr(id, -1)), CDenominator ) = CNumerator
;
begin
open c_my_cursor( PNumerator, PDenominator );
...
end;