Наши партнеры








Книги по Linux (с отзывами читателей)

Библиотека сайта rus-linux.net

На главную -> MyLDP -> Электронные книги по ОС Linux
Цилюрик О.И. Linux-инструменты для Windows-программистов
Назад Компиляция и сборка приложений Вперед

Данные в динамической библиотеке

До сих пор мы говорили только о функциях в библиотеке, вызываемых из кода приложения. А что, если библиотека содержит специфические данные, или даже модифицируются по ходу выполнения приложения? Сделаем библиотеку и соответствующую ей задачу, которые ответят нам на этот вопрос. Сначала смотрим код библиотеки:

lib.h :

#define BUF_SIZE 200 
void put_new_string( const char *s ); 
void get_new_string( char *s ); 
lib.c :
#include <string.h> 
#include "lib.h" 

static char buffer[ BUF_SIZE + 1 ] = "initial buffer state!\n"; 

void put_new_string( const char *s ) { 
   strcpy( buffer, s ); 
} 

void get_new_string( char *s ) { 
   strcpy( s, buffer ); 
} 

Вот, собственно, и вся библиотека: она экспортирует два имени, но функция put_new_string() изменяет содержимое внутреннего статического (невидимого внаружу) буфера buffer. И соответствующий пользовательский процесс, который на каждом прохождении цикла индицирует значение, считанное им библиотечным вызовом get_new_string(), после чего обновляет по put_new_string() это содержимое считанной с консоли строкой:

prog.c :

#include "lib.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 

void put( char* msg ) { 
   time_t t; 
   time( &t ); 
   struct tm *m = localtime( &t ); 
   printf( "%02d:%02d :\t%s", m->tm_min, m->tm_sec, msg ); 
} 

int main( int argc, char *argv[] ) { 
   char buffer[ BUF_SIZE + 1 ] = ""; 
   while( 1 ) { 
      get_new_string( buffer ); 
      put( buffer ); 
      fprintf( stdout, "> " ); 
      fflush( stdout ); 
      fgets( buffer, sizeof( buffer ), stdin ); 
      put( buffer ); 
      put_new_string( buffer ); 
      printf( "--------------------------\n" ); 
   } 
} 

Для ясности — сценарий и процесс сборки:

Makefile :

LSRC = lib 
LNAME = new 
LIB = lib$(LNAME) 
PROG = prog 

all: $(LIB) $(PROG) 

$(LIB):        $(LSRC).c $(LSRC).h 
                gcc -c -fpic -fPIC -shared $(LSRC).c -o $(LSRC).o 
                gcc -shared -o $(LIB).so $(LSRC).o 
                rm -f $(LSRC).o 

$(PROG):        $(PROG).c $(LIB) 
                gcc $< -Bdynamic -L./ -l$(LNAME) -o $@ 

$ make 
gcc -c -fpic -fPIC -shared lib.c -o lib.o 
gcc -shared  -o libnew.so lib.o 
rm -f lib.o 
gcc prog.c -Bdynamic -L./ -lnew -o prog 

$ ls 
lib.c  lib.h libnew.so  Makefile  prog  prog.c 

А теперь выполняем c двух различных терминалов два независимых экземпляра полученной программы prog, которые используют единый общий экземпляр разделяемой библиотеки libnew.so:

$ export LD_LIBRARY_PATH=`pwd` 

$ ./prog 
34:41 : initial buffer state! 
> 2-й терминал 
35:15 : 2-й терминал 
--------------------------
35:15 : 2-й терминал 
> повторение со второго терминала 
35:53 : повторение со второго терминала 
--------------------------
35:53 : повторение со второго терминала 
> ^C 

$ export LD_LIBRARY_PATH=`pwd` 
$ ./prog 
34:52 : initial buffer state! 
> 1-й терминал 
35:05 : 1-й терминал 
--------------------------
35:05 : 1-й терминал 
> повторение с 1-го терминала 
35:34 : повторение с 1-го терминала 
--------------------------
35:34 : повторение с 1-го терминала 
> ^C 

Прекрасно видно (по чередующимся временным меткам операции, формат <минуты>:<секунды>), что каждый экземпляр программы работает со своей копией буфера, не затирая данные параллельно работающего экземпляра программы: при первой модификации области данных экземпляру создаётся своя независимая копия данных (COW — copy on write).


Предыдущий раздел: Оглавление Следующий раздел:
Подмена имён   Некоторые сравнения