library linking on LINUX

本文通过两个示例程序,展示了如何使用信号量实现线程间的同步。包括静态链接和动态链接两种方式,并提供了Makefile构建文件及环境配置说明。

file list: original files were from chapter 20 of Linux系统分析与高级编程技术

 1. hello2.c --test bench for static linking and linking with shared lib

#include "Semaphore.h"
#include 
<stdio.h>

void print_message_function( void *ptr );
Semaphore child_counter;
Semaphore worlds_turn;

main( )
{
    pthread_t thread1, thread2;
    
char *message1 = "Hello";
    
char *message2 = "World " ;
    semaphore_init( 
&child_counter );
    semaphore_init( 
&worlds_turn );
    semaphore_down( 
&worlds_turn ); /* world goes second */
    semaphore_decrement( 
&child_counter ); /* value now 0 */
    semaphore_decrement( 
&child_counter ); /* value now -1 */
    
/*
     * * child_counter now must be up-ed 2 times for a thread blocked on it
     * * to be released
     * *
    
*/

    pthread_create( 
&thread1, NULL,(void *&print_message_function, (void *) message1);
    semaphore_down( 
&worlds_turn );
    pthread_create( 
&thread2, NULL,(void *&print_message_function, (void *) message2);
    semaphore_down( 
&child_counter );
    
/* not really necessary to destroy since we are exiting anyway */
    semaphore_destroy ( 
&child_counter );
    semaphore_destroy ( 
&worlds_turn );
    exit( 
0 ) ;
}


void print_message_function( void *ptr )
{
    
char *message;
    message 
= (char *) ptr;
    printf(
"%s ", message);
    fflush(stdout);
    semaphore_up( 
&worlds_turn );
    semaphore_up( 
&child_counter );
    pthread_exit( 
0 ) ;
}

 2. hello2_dl.c -- test bench for dynamic linking

#include <stdio.h>
#include 
<stdlib.h>
#include 
<dlfcn.h>
#include 
"Semaphore.h"

void print_message_function( void *ptr );
Semaphore child_counter;
Semaphore worlds_turn;

void (*initfcn)(Semaphore* s);
void (*destroyfcn)(Semaphore* s);
int (*downfcn)(Semaphore* s);
int (*upfcn)(Semaphore* s);
int (*decfcn)(Semaphore* s);

int main( )
{
    pthread_t thread1, thread2;
    
char *message1 = "Hello";
    
char *message2 = "World ";

    
void *handle;
    
const char *errmsg;

    handle 
= dlopen("libSemaphore.so", RTLD_NOW);
    
if(handle == NULL) {
        fprintf(stderr, 
"Failed to load libSempahore.so: %s ", dlerror());
        exit(EXIT_FAILURE);
    }

    dlerror();

    initfcn 
= dlsym(handle, "semaphore_init");
    
if((errmsg = dlerror()) != NULL) {
        fprintf(stderr, 
"Didn't find semaphore_init(): %s ", errmsg);
        exit(EXIT_FAILURE);
    }


    downfcn 
= dlsym(handle, "semaphore_down");
    
if((errmsg = dlerror()) != NULL) {
        fprintf(stderr, 
"Didn't find semaphore_down(): %s ", errmsg);
        exit(EXIT_FAILURE);
    }


   upfcn 
= dlsym(handle, "semaphore_up");
    
if((errmsg = dlerror()) != NULL) {
        fprintf(stderr, 
"Didn't find semaphore_up(): %s ", errmsg);
        exit(EXIT_FAILURE);
    }


    decfcn 
= dlsym(handle, "semaphore_decrement");
    
if((errmsg = dlerror()) != NULL) {
        fprintf(stderr, 
"Didn't find semaphore_decrement(): %s ", errmsg);
        exit(EXIT_FAILURE);
    }



    destroyfcn 
= dlsym(handle, "semaphore_destroy");
    
if((errmsg = dlerror()) != NULL) {
        fprintf(stderr, 
"Didn't find semaphore_destroy(): %s ", errmsg);
        exit(EXIT_FAILURE);
    }


    initfcn( 
&child_counter );
    initfcn( 
&worlds_turn );
    downfcn( 
&worlds_turn ); /* world goes second */
    decfcn( 
&child_counter ); /* value now 0 */
    decfcn( 
&child_counter ); /* value now -1 */
    
/*
     * * child_counter now must be up-ed 2 times for a thread blocked on it
     * * to be released
     * *
    
*/

    pthread_create( 
&thread1, NULL,(void *&print_message_function, (void *) message1);
    downfcn( 
&worlds_turn );
    pthread_create( 
&thread2, NULL,(void *&print_message_function, (void *) message2);
    downfcn( 
&child_counter );
    
/* not really necessary to destroy since we are exiting anyway */
    destroyfcn ( 
&child_counter );
    destroyfcn ( 
&worlds_turn );
    dlclose(handle);
    exit( 
0 ) ;
}


void print_message_function( void *ptr )
{
    
char *message;
    message 
= (char *) ptr;
    printf(
"%s ", message);
    fflush(stdout);
    upfcn( 
&worlds_turn );
    upfcn( 
&child_counter );
    pthread_exit( 
0 ) ;
}

 

3. Semaphore.h Semaphore.c -- lib file

#ifndef SEMAPHORES
#define SEMAPHORES
#include 
<pthread.h>

typedef 
struct Semaphore
{
    
int v;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
}
 Semaphore;

int semaphore_down (Semaphore * s);
int semaphore_decrement (Semaphore * s);
int semaphore_up (Semaphore * s);
void semaphore_destroy (Semaphore * s);
void semaphore_init (Semaphore * s);
int semaphore_value (Semaphore * s);
int tw_pthread_cond_signal (pthread_cond_t * c);
int tw_pthread_cond_wait (pthread_cond_t * c, pthread_mutex_t * m);
int tw_pthread_mutex_unlock (pthread_mutex_t * m);
int tw_pthread_mutex_lock (pthread_mutex_t * m);
void do_error (char *msg);

# endif

 

#include "Semaphore.h"
/*
* function must be called prior to semaphore use.
*
*/

void
semaphore_init (Semaphore 
* s)
{
    s
->= 1;
    
if (pthread_mutex_init (&(s->mutex), NULL) == -1)
        do_error (
"Error setting up semaphore mutex");
    
if (pthread_cond_init (&(s->cond), NULL) == -1)
        do_error (
"Error setting up semaphore condition signal");
}


/*
* function should be called when there is no longer a need for
* the semaphore.
*/

void
semaphore_destroy (Semaphore 
* s)
{
    
if (pthread_mutex_destroy (&(s->mutex)) == -1)
        do_error (
"Error destroying semaphore mutex");
    
if (pthread_cond_destroy (&(s->cond)) == -1)
        do_error (
"Error destroying semaphore condition signal");
}


/*
* function increments the semaphore and signals any threads that
* * are blocked waiting a change in the semaphore.
*
*/

int
semaphore_up (Semaphore 
* s)
{
    
int value_after_op;
    tw_pthread_mutex_lock (
&(s->mutex));
    (s
->v)++;
    value_after_op 
= s->v;
    tw_pthread_mutex_unlock (
&(s->mutex));
    tw_pthread_cond_signal (
&(s->cond));
    
return (value_after_op);
}


/*
* function decrements the semaphore and blocks if the semaphore is
* * <= 0 until another thread signals a change.
*
*/

int
semaphore_down (Semaphore 
* s)
{
    
int value_after_op;
    tw_pthread_mutex_lock (
&(s->mutex));
    
while (s-><= 0)
    
{
        tw_pthread_cond_wait (
&(s->cond), &(s->mutex));
    }

    (s
->v)--;
    value_after_op 
= s->v;
    tw_pthread_mutex_unlock (
&(s->mutex));
    
return (value_after_op);
}


/*
* function does NOT block but simply decrements the semaphore.
 * should not be used instead of down -- only for programs where
 * multiple threads must up on a semaphore before another thread
 * can go down, i.e., allows programmer to set the semaphore to
 * a negative value prior to using it for synchronization.
 *
*/

int
semaphore_decrement (Semaphore 
* s)
{
    
int value_after_op;
    tw_pthread_mutex_lock (
&(s->mutex));
    s
->v--;
    value_after_op 
= s->v;
    tw_pthread_mutex_unlock (
&(s->mutex));
    
return (value_after_op);
}


/*
* function returns the value of the semaphore at the time the
* critical section is accessed. obviously the value is not guarenteed
* after the function unlocks the critical section. provided only
* for casual debugging, a better approach is for the programmar to
* protect one semaphore with another and then check its value.
* an alternative is to simply record the value returned by semaphore_up
* or semaphore_down.
*
*/

int
semaphore_value (Semaphore 
* s)
{
    
/* not for sync */
    
int value_after_op;
    tw_pthread_mutex_lock (
&(s->mutex));
    value_after_op 
= s->v;
    tw_pthread_mutex_unlock (
&(s->mutex));
    
return (value_after_op);
}


/* -------------------------------------------------------------------- */
/* The following functions replace standard library functions in that */
/* they exit on any error returned from the system calls. Saves us */
/* from having to check each and every call above. */
/* -------------------------------------------------------------------- */
int
tw_pthread_mutex_unlock (pthread_mutex_t 
* m)
{
    
int return_value;
    
if ((return_value = pthread_mutex_unlock(m)) == -1)
        do_error (
"pthread_mutex_unlock");
    
return (return_value);
}

int
tw_pthread_mutex_lock (pthread_mutex_t 
* m)
{
    
int return_value;
    
if ((return_value = pthread_mutex_lock(m)) == -1)
        do_error (
"pthread_mutex_lock");
    
return (return_value);
}

int
tw_pthread_cond_wait (pthread_cond_t 
* c, pthread_mutex_t * m)
{
    
int return_value;
    
if ((return_value = pthread_cond_wait(c, m)) == -1)
        do_error (
"pthread_cond_wait");
    
return (return_value);
}

int
tw_pthread_cond_signal (pthread_cond_t 
* c)
{
    
int return_value;
    
if ((return_value = pthread_cond_signal(c)) == -1)
        do_error (
"pthread_cond_signal");
    
return (return_value);
}


/*
* function just prints an error message and exits
* *
*/

void
do_error (
char *msg)
{
    perror (msg);
    exit (
1);
}

 4. Makefile:

all: hello2_static1 hello2_static2  Semaphore.o libSemaphore.a libSemaphore.so hello2_shared hello2_dynamic

#static linking program
#hello2_static1 and hello2_static2 are same
hello2_static1: hello2.c libSemaphore.a
        gcc  hello2.c -o hello2_static1 -lSemaphore -L. -lpthread
hello2_static2: hello2.c Semaphore.o
        gcc hello2.c Semaphore.o -o hello2_static2 -lpthread

Semaphore.o: Semaphore.c
        gcc  -Wall -c Semaphore.c -o Semaphore.o

#create archive for object file
libSemaphore.a: Semaphore.o
        ar rcs libSemaphore.a Semaphore.o

#linking with shared lib
#before executing: setenv LD_LIBRARY_PATH $PWD
hello2_shared: hello2.c libSemaphore.so
        gcc  hello2.c -o hello2_shared -lSemaphore -L. -lpthread

libSemaphore.so: Semaphore.c
        gcc -fPIC -Wall -c Semaphore.c -o Semaphore_PIC.o
        gcc  -Wall -shared -Wl
,-soname,libSemaphore.so.1 -o libSemaphore.so.1.0.0 Semaphore_PIC.o -lc
        ln -s libSemaphore.so
.1.0.0 libSemaphore.so.1
        ln -s libSemaphore.so
.1.0.0 libSemaphore.so

#create object with dynamic linking
hello2_dynamic: hello2_dl.c libSemaphore.so
        gcc  -Wall hello2_dl.c -ldl -o hello2_dynamic -lpthread

clean:
        rm -rf hello2_static1 hello2_static2 Semaphore.o Semaphore_PIC.o libSemaphore.a libSemaphore.so libSemaphore.so
.1 libSemaphore.so.1.0.0 hello2_shared hello2_dynamic

 
3 kinds of set searching path for shared libraries:
(1) setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH }:$YOURPATH
(2) add your serching path to /etc/ld.so.conf, then run ldconfig to update /etc/ld.so.cashe under root account
(3) put your shared libs ot /usr/lib, then create soname links to the specific libs, and run ldconfig under root account to update the cache
 
 2 useful commands:
(1) "ldd" shows needed shared libraries for the file:
ldd hello2_static1 :
libpthread.so.0 => /lib/i686/libpthread.so.0 (0x40033000)
libc.so.6 => /lib/i686/libc.so.6 (0x40048000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
ldd hello2_shared :
libSemaphore.so.1 => /rdhome/robin/programming/Linux_System_Analysis_And_Advanced_Programming_Tech/ch20/libSemaphore.so.1 (0x40018000)
libpthread.so.0 => /lib/i686/libpthread.so.0 (0x40036000)
libc.so.6 => /lib/i686/libc.so.6 (0x4004b000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
ldd hello2_dynamic:
libdl.so.2 => /lib/libdl.so.2 (0x40033000)
libpthread.so.0 => /lib/i686/libpthread.so.0 (0x40037000)
libc.so.6 => /lib/i686/libc.so.6 (0x4004c000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
(2) "nm" shows all symbols in the object
nm libSemaphore.a:
Semaphore.o:
000002dc T do_error
         U exit
00000000 t gcc2_compiled.
         U perror
         U pthread_cond_destroy
         U pthread_cond_init
         U pthread_cond_signal
         U pthread_cond_wait
         U pthread_mutex_destroy
         U pthread_mutex_init
         U pthread_mutex_lock
         U pthread_mutex_unlock
0000017c T semaphore_decrement
00000068 T semaphore_destroy
00000114 T semaphore_down
00000000 T semaphore_init
000000c4 T semaphore_up
000001bc T semaphore_value
000002a4 T tw_pthread_cond_signal
00000268 T tw_pthread_cond_wait
00000230 T tw_pthread_mutex_lock
000001f8 T tw_pthread_mutex_unlock

SocketTool4 是一款实用的 Socket 网络通信调试工具,主要用于 TCP、UDP 协议的数据收发测试和网络连接验证。它可以模拟 TCP Client、TCP Server、UDP 发送端和 UDP 接收端,方便开发者在没有完整业务程序的情况下,快速构造网络通信环境,验证设备或程序的 Socket 通信功能。在实际开发中,SocketTool4 常用于嵌入式设备联网调试、上位机软件通信测试、物联网设备联调、服务器接口测试、自定义协议调试、局域网通信验证等场景。开发者可以使用它连接目标服务器,监听指定端口,发送测试数据,接收设备返回的数据,从而判断网络链路、端口监听、协议格式和数据交互是否正常。SocketTool4 支持 TCP 和 UDP 两种常见传输协议。使用 TCP 模式时,可以作为客户端主动连接服务器,也可以作为服务端监听端口等待客户端连接;使用 UDP 模式时,可以向指定 IP 和端口发送数据,也可以监听本地端口接收数据。对于需要调试网络模块、网口设备、串口转网口模块、WiFi 模块、4G 模块、工业控制设备或嵌入式 Linux 网络程序的场景非常方便。该工具通常支持文本数据和十六进制数据收发,便于调试 ASCII 协议、二进制协议和私有通信协议。开发者可以通过发送固定测试帧、心跳包、控制命令或模拟业务数据,观察对端响应是否符合预期。相比直接编写临时测试程序,SocketTool4 使用更简单、上手更快,适合日常网络问题定位和协议联调。适用场景包括:1. TCP 客户端连接测试2. TCP 服务端监听测试3. UDP 数据发送和接收测试4. 嵌入式设备网络通信调试5. 上位机与设备通信联调6. 私有协议数据帧验证7. 十六进制数据包收发测试8. 局域网端口连通性验证9. Socket 程序开发辅助测试10. 物联网
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值