INF: Threads Must Cooperate Accessing Run-Time Data Structures

ID Number: Q73516

5.10 6.00 6.00a

OS/2

Summary:

In Microsoft C versions 5.1, 6.0, and 6.0a, with an OS/2 application

that uses the multithreaded C run-time library functions, there are

many tables and data structures that all the threads must share. This

is done by placing a lock on the part of the table or data structure

that must remain unchanged during a particular run-time operation.

Although the run-time code performs all the data locking and unlocking

as necessary, a little planning and forethought is needed when

designing a multithreaded application to ensure that the application

will not have to stop and wait for slower operations because of these

locks.

More Information:

An example of data that all threads must share is the table of file

handles that is maintained for file I/O. If one thread is performing a

read or write to a particular file, all other threads must be blocked

from using or modifying that file handle. If the other threads were

not prevented from modifying that file handle, there is no way to

predict what might occur. For example, a separate thread could close

the file in the middle of an I/O operation.

Likewise, on a larger scale, a file open operation must have a lock on

the entire file handle table if it is to know which file handles are

used and which are available at a particular instant. If none are

available, the operation must fail with the appropriate return code.

To lock the entire table, there must be no individual file handle

locks on the table at the time.

It is especially important to be aware of these interdependencies

between individual field locks and global table locks so that a

program will not spend an inordinate amount of time waiting on blocked

threads. The example program below illustrates one such situation that

can arise if these dependencies are ignored during program design.

In the example, Thread 1 (the main thread) opens a file, spawns a

second thread, and then prompts the user for input. The operation of

prompting the user for input places a lock on the stdin file handle.

Thread 2, meanwhile, attempts to write to the file thread 1 opened.

This proceeds immediately because there is no lock on the table or

that particular file handle. Thread 2 then attempts to open a new

file, but the open operation requires a lock on the entire table.

Because the main thread has a lock on one of the handles in the table

(stdin), the operation must wait until the lock is released. Once the

main thread has released its lock on stdin, the open operation in the

second thread continues and returns the appropriate result. The sample

program output below indicates that this is indeed what happens.

Sample Code

-----------

/* Compile options needed: /MT

*/

#define INCL_DOS

#include <os2.h>

#include <stdio.h>

#include <string.h>

#include <process.h>

void thread(void);

void main(void);

FILE *fptr1;

FILE *fptr2;

void main()

{

int i = 1;

char name[25];

if( NULL != (fptr1 = fopen( "tstfle", "w+" )))

printf( "\nThread one has opened a test file.\n" );

else

printf( "\nThread one has failed to open a test file.\n" );

if( _beginthread( thread, NULL, 4096, NULL ) == -1 )

{

printf( "\nCan not start second thread.\n" );

return( -1 );

}

printf( "Thread one is prompting for five names.\n" );

while( i <= 5 )

{

printf( "\nEnter name %d: ", i );

gets( name );

i++;

}

DosSleep( 500L );

}

void thread( )

{

int count;

DosSleep( 500L );

if( fptr1 != NULL )

{

count = fprintf( fptr1, "This is a test.\n" );

printf( "\n\tThread two has written %d chars to thread one's ");

printf( "test file.\n", count );

}

DosSleep( 500L );

if (NULL != (fptr2 = fopen( "tstfle2", "w+" )))

printf( "\n\tThread two has opened a test file.\n" );

else

printf( "\n\tThread two has failed to open a test file.\n" );

}

Program Output

--------------

Thread one has opened a test file.

Thread one is prompting for five names.

Enter name 1:

Thread two has written 16 characters to thread one's test file.

<name1>

Enter name 2: <name2>

Enter name 3: <name3>

Enter name 4: <name4>

Enter name 5: <name5>

Thread two has opened a test file.

Additional reference words: 5.1 5.10 6.0 6.00 6.0a 6.00a