Atomicity


 
Thread Tools Search this Thread
Top Forums Programming Atomicity
# 1  
Old 05-03-2004
Atomicity

I am working on a primitive project ported on AIX Unix Box. Earlier this system used to run on VMS VAX and DEC Alpha system. The major source code files are written in FROTRAN.

Across process data are exchanged through FROTRAN COMMONS and a specific locking mechanism is implemented for resource synchronization. Data for exchange are stored in FROTRAN Array in COMMONS. During addition to the bottom of the array and removal from the top, a specific position of the array is marked as 1 or 0 meaning that array can be accessed or cannot. Based upon these values the action on arrays would be taken. I hope that I am clear.

They used LIB$BBSSI() system call to lock the list and LIB$BBCCI() system call to release the list from lock state in VMS. I presume that this would be atomic cause of which process where in synchronization.

During porting of the same software in Tru64 they swapped the same routines with C subroutines _TESTBITSSI() and _TESTBITCCI() calls.

The problem came when they ported it to AIX. Due to lack of technology specifications we are unable to have atomic locking mechanism. Hence the issue is that two or more process is able to detect that they can act on a same array resulting on an unpredictable behavior.

We need a solution for the problem. I though of a solution but I don't know that in multi-process environment whether the solution would work or not. Please provide your necessary input and ensure that the code does leads to a DEADLOCK.
:

During the process startup we would store the required address our interest. Say for example we have 3-array list and list lock index is 1. So if the arrays are named as A, B, D then we will store the address of A (1), B (1) and D (1) in ‘C' array of pointers *list_arr[3] (list_arr[0], list_arr[1], list_arr[2]).
Now LOCK() and REL() subroutine would be called across process running in different address space.

LOCK(int *bit_pos, int *address)
{
.......
.......
/* For One specific address */
RERUN:
if ( address == list_arr[0] )
{
if ( shared_variable_One == 0 ) /* Variable Shared Across Processes */
{
shared_variable_One = getpid ( ) ;
}
if (shared_variable_One == getpid ( ) )
{
if ( ++ shared_variable_two > 1 ) /* Variable Shared Across Processes Initially initialized as 0*/
goto RERUN:
/* Set the bit value */
shared_variable_One = 0 ;
shared_variable_two = 0 ;
}
else
goto RERUN;
}

.......................
.......................
}
The same can be implemented for REL(int *bit_pos, int *address).

These subroutines would then be called through FROTANS subroutines.

I have had thought about using SEMAPHORES but then we had to use 3 semaphores (as in this example) such that operation on one address by one process does not blocks operation on other address which is being accessed by multiple process.

Thanks in advance.

Last edited by S.P.Prasad; 05-03-2004 at 03:34 AM..
# 2  
Old 05-03-2004
First of all I would like to state that the pseudo-code I have written in my initial post needs modification. Instead of writing LOCK () and REL() as two separate functions, it would be only one subroutine LOCK_REL() implementing the pseudo-code.

Quote:
How are the variables shared - using shared memory?
Yes. This concept is already implemented in the project. All I need to is add up the required variables.

Quote:
No, you can also use a single lock for all resources, so that you might get heavy lock contention but still permit multiple processes to operate independently.
I studied the pseudo-code but that's what exactly we do not want. For example there are 10 process. Assume 2 different process would like to implement LOCK on the array and while 3 different process tries to REL the LOCK on the same array. Only one of the process should succeed for a specific array operation.

Further more of the remaining 5, 3 different process are trying to implement LOCK on 3 different arrays and 2 are REL two separate arrays, then they very well should. I mean they should not wait other wise timing would become a major issue i.e. time to process one transaction would increase.

Here's a sample view of what I would like to implement atomically:

Process'xx'1'xxxxx'2'xxxxx'3'xxxx'4'xxxxx'5'xxxxx'6'
Array'xxxx'A'xxxxx'B'xxxxx'C'xxxx'D'xxxxx'E'xxxxx'F'

xxxxxxxx ..... xxxx..... xx..... xxxx..... xxx......xxx.........
xxxxxxxxL(D)xxxxL(D)xxR(D)xxxxL(E)xxxR(F)xxxL(A)
xxxxxxxx ..... xxxx..... xx..... xxxx..... xxx......xxx.........

Where L stands for LOCK and R stands for REL the lock on array passed as arguments and value at array index 1 states whether array is locked ( value 1 ) or unlock ( value 0 ) . Please ignore the x's as I have put it for alignment purpose

I hope that I am clear in my requirement.

Thanks in advance.

Last edited by S.P.Prasad; 05-03-2004 at 09:55 AM..
# 3  
Old 05-03-2004
First of all I would thank Driver for all the technical support and aid that he has provided.

Driver as you have stated that:

Quote:
lock(resources.semid);
if (data[1].used == 0 && data[2].used == 0) {
data[1].used = 1;
data[2].used = 1;
} else {
unlock(resources.semid);
/* Wait for 1 and 2 to become free */
}
unlock(resources.semid);
We have more than 10 process and in each process it has to LOCK or REL the LOCK for a specific array. One specific process cannot lock or release for more than one resource at a time. As per your pseudo-code then we need to have as many number of SEMAPHORES as there are number of arrays and LOCK / REL piece of code should be injected where locking and releasing of the resource comes into picture within the process. That would include a lot of re-work in the project. Will it be time efficient?

That is what I have posted the same in initial post.

Yes your pseudo-code would work fine if through out the processes we make a check that for a specific array the mapped SEMAPHORE key would lock or unlock the resource.

Thanks Driver, your solution is definitely a valuable one. I will build up a set of test executables implementing your pseudo-code.

Also please let me know if the pseudo-code I posted in my initial post is ok or not?

Thanks in advance.

Last edited by S.P.Prasad; 05-03-2004 at 10:34 AM..
# 4  
Old 05-03-2004
Quote:
Originally posted by S.P.Prasad
Also please let me know if the pseudo-code I posted in my initial post is ok or not?
What you're trying to do is code a mutex using only shared memory. And for n processes, not just 2 processes. I'm not qualified to pass judgement on your algorithm, but I wouldn't be surprised if there is a problem with it.

This is like encryption or compression... what you should do is use one of the well known and carefully researched algorithms.

See this page for example.
# 5  
Old 05-04-2004
Thanks Perderabo.

Currently I am going through the algorithms as provided by you in a link.

I would like to put forward my observations in this post. As earlier mentioned the code was ported from VMS to Tru64 to AIX. Now as a part of unit integration, I copied the existing LOCK() and REL() functions in AIX box to that in Tru64 and re-compiled the executables. Surprisingly I did not receive any errors in Tru64. I wonder why ?


And will Shared libraries help us to our problem. We can resist only one copy of functions in the memory and validate which address is getting locked or release and take action accordingly.

Thanks in advance.
# 6  
Old 05-04-2004
To add I just learnt that the AIX system we have runs on dual CPU while that of Tru64 has a single CPU.

Will that make a difference on performance or code behavior?
# 7  
Old 05-04-2004
Thanks for the information, Driver.

Quote:

Process 2 now gets to execute, finds the shared variable zero too and writes its PID to it. Then process 1 gets to execute again and overwrites the PID of the other process.
The second if takes care such that only one process has the right to execute code:

Quote:

if (shared_variable_One = = getpid ( ) )
{
if ( ++ shared_variable_two > 1 ) /* Variable Shared Across Processes Initially initialized as 0*/
goto RERUN:
/* Set the bit value */
shared_variable_One = 0 ;
shared_variable_two = 0 ;
}
I hope that I am clear.

Quote:

I'm now sure why shared libraries come into play now ...
Shared libraries (also called dynamic libraries) are linked into the program in two stages. First, during compile time, the linker verifies that all the symbols (again, functions, variables and the like) required by the program, are either linked into the program, or in one of its shared libraries. However, the object files from the dynamic library are not inserted into the executable file. Instead, when the program is started, a program in the system (called a dynamic loader) checks out which shared libraries were linked with the program, loads them to memory, and attaches them to the copy of the program in memory.

The complex phase of dynamic loading makes launching the program slightly slower, but this is a very insignificant drawback, that is out-weighted by a great advantage - if a second program linked with the same shared library is executed, it can use the same copy of the shared library, thus saving a lot of memory. Only one copy of the library is stored in memory at any given time. This means we can use far less memory to run our programs, and the executable files are much smaller, thus saving a lot of disk space as well.


Hence if I write LOCK() and REL() subroutines as a part of Shared Library and link it to the executable, will not aid me to make the operations atomic. I can easily validate in the subroutines which address is requested for locking and which for release.

Thanks in advance.

I personally thank Driver and Perderabo for their interest shown to solve the issue. Please continue aiding me till we conclude to a unanimous decision.
Login or Register to Ask a Question

Previous Thread | Next Thread
Login or Register to Ask a Question