Linux系统编程之信号量

什么是:信号量(Semaphore)

是一种用于控制多个进程或线程之间同步和互斥访问共享资源的机制。它是由一个整数值和与之关联的一组操作组成的。信号量的主要目的是确保在并发环境中对共享资源的访问是有序的,避免竞争条件和数据不一致性。 信号量的基本操作包括:
  1. 初始化(sem_init): 创建一个新的信号量并初始化其值。
  2. 等待(sem_wait): 如果信号量的值大于零,则将其减一;否则,阻塞当前进程或线程,直到信号量的值变为大于零为止。
  3. 尝试等待(sem_trywait): 类似于等待操作,但不会阻塞,而是立即返回失败,如果信号量的值为零。
  4. 定时等待(sem_timedwait): 在指定的时间内尝试等待,超时则返回失败。
  5. 释放(sem_post): 将信号量的值加一,表示共享资源已经释放或可用。 信号量可用于解决多进程或多线程之间的同步问题,例如确保在访问共享数据之前获得锁,以防止竞争条件的发生。在C语言中,信号量通常使用sem_t类型来表示。

应用于线程 进程间同步

信号量相当于初始化为N的互斥量。

N值表示可以同时访问共享数据区的线程数。

主要应用函数:

sem init函数 初始化

sem_init 函数用于初始化一个未命名的信号量,其解锁及其参数如下:

int sem_init(sem_t *sem, int pshared, unsigned int value);

  • sem:指向要初始化的信号量的指针。
  • pshared:指定信号量的类型,如果为0,则信号量在进程间共享;如果非0,则信号量在进程间不共享,仅在当前进程的线程之间共享。通常设置为0。
  • value:指定信号量的初始值。 示例用法:
#include 
#include 
int main() {
    sem_t mySemaphore;

    // 初始化信号量,初始值为1
    if (sem_init(&mySemaphore, 0, 1) == -1) {
        perror("sem_init");
        return 1;
    }
    // 使用信号量...
    // 销毁信号量
    sem_destroy(&mySemaphore);
    return 0;
}

在这个例子中,sem_init 函数初始化了一个信号量 mySemaphore,并设置初始值为1。在使用完信号量后,可以使用 sem_destroy 函数进行清理。

sem destroy函数 销毁、

sem_destroy 函数用于销毁一个已初始化的信号量,释放与之关联的资源。它的解释及参数如下:

int sem_destroy(sem_t *sem);

  • sem:指向要销毁的信号量的指针。 示例用法:
#include 
#include 
int main() {
    sem_t mySemaphore;

    // 初始化信号量,初始值为1
    if (sem_init(&mySemaphore, 0, 1) == -1) {
        perror("sem_init");
        return 1;
    }
    // 使用信号量...
    // 销毁信号量
    if (sem_destroy(&mySemaphore) == -1) {
        perror("sem_destroy");
        return 1;
    }
    return 0;
}

在这个例子中,sem_destroy 函数用于销毁之前初始化的信号量 mySemaphore。需要注意的是,该函数应在不再使用信号量时调用,以确保释放相关资源。

sem wait函数 加锁

sem_wait 函数用于对信号量进行等待(减1)操作。其解释及参数如下:

int sem_wait(sem_t *sem);

  • sem:指向要等待的信号量的指针。 示例用法:
#include 
#include 
int main() {
    sem_t mySemaphore;

    // 初始化信号量,初始值为1
    if (sem_init(&mySemaphore, 0, 1) == -1) {
        perror("sem_init");
        return 1;
    }
    // 在这里对信号量进行等待(减1)
    if (sem_wait(&mySemaphore) == -1) {
        perror("sem_wait");
        return 1;
    }
    // 使用信号量...
    return 0;
}

在这个例子中,sem_wait 函数用于对初始化为1的信号量 mySemaphore 进行等待操作。如果信号量的值为0,sem_wait 会阻塞,直到信号量的值大于0为止。

sem trywait函数

sem_trywait 函数用于尝试对信号量进行等待(减1)操作,但不会阻塞进程。其解释及参数如下:

int sem_trywait(sem_t *sem);

  • sem:指向要尝试等待的信号量的指针。 示例用法:
#include 
#include 
int main() {
    sem_t mySemaphore;

    // 初始化信号量,初始值为1
    if (sem_init(&mySemaphore, 0, 1) == -1) {
        perror("sem_init");
        return 1;
    }
    // 尝试对信号量进行等待(减1),不会阻塞
    if (sem_trywait(&mySemaphore) == -1) {
        perror("sem_trywait");
        // 处理无法等待的情况...
    } else {
        // 成功等待,可以使用信号量...
    }
    return 0;
}

在这个例子中,sem_trywait 函数尝试对初始化为1的信号量 mySemaphore 进行等待操作。如果信号量的值为0,它不会阻塞,而是返回失败,你可以根据返回值来处理无法等待的情况。

sem timedwait函数

sem_timedwait 函数用于在指定的时间内尝试对信号量进行等待(减1)操作,如果在规定时间内无法等待成功,则返回错误。其解释及参数如下:

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

  • sem:指向要等待的信号量的指针。
  • abs_timeout:指定等待的绝对时间,使用 struct timespec 结构表示,包括秒和纳秒两个字段。 示例用法:
#include 
#include 
#include 
int main() {
    sem_t mySemaphore;
    struct timespec abs_timeout;
    // 获取当前时间
    clock_gettime(CLOCK_REALTIME, &abs_timeout);
    // 设置等待时间为当前时间加上5秒
    abs_timeout.tv_sec += 5;
    // 初始化信号量,初始值为1
    if (sem_init(&mySemaphore, 0, 1) == -1) {
        perror("sem_init");
        return 1;
    }
    // 在指定时间内尝试对信号量进行等待(减1)
    if (sem_timedwait(&mySemaphore, &abs_timeout) == -1) {
        perror("sem_timedwait");
        // 处理等待超时或其他错误的情况...
    } else {
        // 成功等待,可以使用信号量...
    }
    return 0;
}

在这个例子中,sem_timedwait 函数尝试在指定的等待时间内对初始化为1的信号量 mySemaphore 进行等待操作。如果在规定时间内成功等待,就可以使用信号量;否则,可以根据返回值来处理等待超时或其他错误的情况。

sem post函数 解锁

sem_post 函数用于对信号量进行释放(加1)操作,增加信号量的值。其解释及参数如下:

int sem_post(sem_t *sem);

  • sem:指向要释放的信号量的指针。 示例用法:
#include 
#include 
int main() {
    sem_t mySemaphore;

    // 初始化信号量,初始值为1
    if (sem_init(&mySemaphore, 0, 1) == -1) {
        perror("sem_init");
        return 1;
    }
    // 在这里对信号量进行释放(加1)
    if (sem_post(&mySemaphore) == -1) {
        perror("sem_post");
        return 1;
    }
    // 使用信号量...
    return 0;
}

在这个例子中,sem_post 函数用于对初始化为1的信号量 mySemaphore 进行释放操作,增加其值。这通常用于通知其他等待该信号量的进程或线程,可以继续执行了。

以上六个函数的返回值都是:成功返回0,失败返回-1,同时设置errno(注意他们木有pthread前缀)

sem_t类型,本质仍是结构体。但应用期间简单看作为整数

sem_t sem;规定信号量sem不能<0。头文件

信号量基本操作:

sem_wait:

  1. xh1量大于0,则信号量—
  2. 信号量等于0.则造成线程阻塞。

sem_post:

  1. 将信号量++,同时唤醒阻塞在信号量上的线程,但由于sem_t的实现对用户隐藏,所以所谓的++ —操作自能通过函数来实现 而不能直接++ —符号。
  2. 信号量的初值,决定占用信号量的线程的个数。
  3. 当信号量的值为N时,再次++就会阻塞。

你可能感兴趣的:(Linux,linux,算法,运维)