Linux信号量semaphore

信号量:

先从Semaphore看起

免不了一些啰嗦的话语……

Semaphore

信号量(Semaphore)是一种用于线程同步和进程间同步的机制。它是一种整数值,用于控制访问共享资源的线程数量。

信号量有两种操作:V(sem_post)操作和 P(sem_wait)操作。

V操作会将信号量的值加1,P操作会将信号量的值减1。当信号量的值为0时,再执行P操作就会阻塞,直到信号量的值变为正数。

信号量可以用于实现各种同步机制,如生产者和消费者模型,读者和写者模型等等。

信号量在操作系统中也是非常常见的,比如Linux中的System VIPC,POSIX信号量,在这些系统中都有提供相应的API来支持信号量的使用。

System V IPC (拓展)

System V IPC即System V Inter-Process Communication,是指System V操作系统中提供的进程间通信机制。
它包括三种通信机制:信号量(semaphore)、共享内存(shared memory)和消息队列(message queue)。

1、信号量(semaphore)主要用于进程间同步,可以用来控制对共享资源的访问。

2、共享内存(shared memory)主要用于进程间的数据传递,可以在不同进程间共享同一块内存空间。

3、消息队列(message queue)主要用于进程间的消息传递,可以在不同进程间传递消息。

System V IPC是早期操作系统的一种实现方式,现在已经被POSIX IPC取代。

了解POSIX IPC(拓展)

POSIX IPC,即POSIX Inter-Process Communication,是指IEEE POSIX标准中提供的进程间通信机制。与 System V IPC 类似, POSIX IPC 也包括信号量(semaphore)、共享内存(shared memory)和消息队列(message queue)三种通信机制。

POSIX信号量与System V信号量类似,主要用于进程间同步,可以用来控制对共享资源的访问。

POSIX共享内存与System V共享内存类似,主要用于进程间的数据传递,可以在不同进程间共享同一块内存空间。

POSIX消息队列与System V消息队列类似,主要用于进程间的消息传递,可以在不同进程间传递消息。

与 System V IPC 不同的是, POSIX IPC 为每种通信机制提供了标准的C语言接口,使得程序员可以在不同的操作系统中使用相同的接口进行进程间通信。这样可以提高代码的可移植性。

POSIX IPC 是当前主流的进程间通信机制,在大多数操作系统中都提供了对应的实现。

POSIX (拓展)

POSIX信号量是 POSIX Inter-Process Communication (IPC) 标准中提供的一种同步机制。它提供了一组标准的C语言接口,用于实现进程间同步。

POSIX信号量与System V信号量和semaphore类似,用于控制对共享资源的访问。它支持两种操作:P操作和V操作。P操作会将信号量的值减1,如果值为0,则阻塞;V操作会将信号量的值加1,如果有其他进程正在阻塞,则唤醒其中一个进程。

POSIX信号量支持多种类型的信号量,包括互斥信号量、计数信号量和超时信号量等。互斥信号量用于在多个进程间控制互斥访问共享资源,计数信号量用于控制对共享资源的访问数量,超时信号量则可以设置超时时间来等待信号量。

POSIX信号量可以在多种平台上使用,如Linux, Unix, MacOS等。 通过使用POSIX信号量,可以简化同步编程,并且可以保证代码在不同平台上的可移植性。

semaphore.h

semaphore.h是C语言编程中的一个标准头文件,它提供了用于操作信号量的函数。这些函数可以用于实现进程间同步和线程间同步。

semaphore.h中的一些常用函数包括:

sem_init():初始化信号量
sem_wait():执行P操作,即将信号量的值减1
sem_post():执行V操作,即将信号量的值加1
sem_getvalue():获取信号量的当前值
sem_destroy():销毁信号量

还有其他一些函数可以用于获取信号量的属性,设置超时等。

semaphore.h头文件在不同平台中实现有所不同,但大多数平台都支持这些函数。

其他不常用函数

除了sem_init,sem_wait,sem_post,sem_getvalue,sem_destroy外,还有如下函数:
sem_trywait() : 尝试将信号量的值减1,如果信号量的值为0则立即返回失败
sem_timedwait() : 带有超时时间的sem_wait()函数,如果在超时时间内信号量的值仍为0,则返回失败
sem_open() : 用于在多个进程间共享信号量
sem_close() : 用于关闭一个信号量
sem_unlink() : 用于删除一个信号量

在使用这些函数时,需要注意信号量的初始化,使用方式,以及对于返回值的判断。

1、sem_init();

sem_init()semaphore.h 头文件中定义的函数。它是用于初始化信号量的函数。

该函数的第一个参数是信号量指针第二个参数表示信号量的属性,一般设置为0第三个参数表示信号量的初始值

该函数通常在程序开始时调用,用于初始化信号量,为后续的信号量操作做好准备。

另外还需要注意的是,当不再使用信号量时,需要调用sem_destroy()函数来销毁信号量,释放相关资源。

sem_init()函数用于初始化一个信号量。它有三个参数:

sem:指向要初始化的信号量的指针。
pshared:指示信号量是否用于多个进程间共享。如果pshared 为0,则信号量只能在当前进程中使用;如果pshared 为非0值,则信号量可以在多个进程中使用。
value:初始值,表示信号量初始时可以有多少个线程或进程同时访问共享资源。

例如:

sem_t mysem;
sem_init(&mysem, 0, 1);

这个例子中会创建一个叫 mysem的信号量并初始化它的值为1,不能在多进程之间共享

需要注意的是,sem_init()函数只能在信号量未被初始化时使用。如果在已经初始化的信号量上再次调用sem_init()函数,会产生未定义的结果。

在使用完信号量之后,需要使用sem_destroy()函数释放信号量占用的系统资源。

信号量是一种常用的同步机制,常用来控制多线程或多进程对共享资源的访问,避免竞争条件和死锁的产生。在使用信号量时需要谨慎控制信号量的值,避免超过初始化时的值。

2、sem_wait();

sem_wait()semaphore.h 头文件中定义的函数。它是用于信号量操作的函数之一,主要用于等待信号量的值变为正值。

当调用 sem_wait() 时,如果信号量的值大于0,则将信号量的值减1,并立即返回;否则当前线程将会被阻塞,直到信号量的值变为正值,才会减1并返回。

这个函数主要是用于同步,保证共享资源的安全性。比如在生产者和消费者模型中,就需要用到这个函数来保证生产者不会生产过多的数据,消费者也不会消费过多的数据,从而保证缓冲区的安全性。

sem_wait()函数用于执行P操作,即将信号量的值减1。如果信号量的值为0,则会阻塞,直到信号量的值变为正数。

这个函数只有一个参数,即要进行操作的信号量。

例如:

sem_t mysem;
sem_init(&mysem, 0, 1);
sem_wait(&mysem);

这个例子中会将 mysem信号量的值减1,如果mysem信号量的值为0,那么当前线程就会被阻塞。

使用sem_wait()函数可以在线程或进程之间进行同步,避免竞争条件或死锁的产生。当信号量的值为0时,调用sem_wait()函数的线程或进程会被阻塞,直到有其他线程或进程使用sem_post()函数将信号量的值增加。

需要注意的是,使用sem_wait()函数阻塞线程或进程时需要考虑程序的正确性和性能问题。

3、sem_post();

sem_post() semaphore.h 头文件中定义的函数。它也是用于信号量操作的函数之一,主要用于增加信号量的值。
当调用 sem_post() 时,将信号量的值加1。如果此时有其它线程因调用 sem_wait() 被阻塞,则会唤醒其中一个线程。
sem_wait()类似,sem_post()主要用于同步,比如在生产者和消费者模型中,就需要用到这个函数来保证生产者和消费者之间的协调。
比如生产者生产完数据后发送信号给消费者来消费数据。

sem_post()函数用于执行V操作,即将信号量的值加1。如果有其他线程正在阻塞在sem_wait()函数上,则唤醒其中一个线程。

这个函数只有一个参数,即要进行操作的信号量。

例如:

sem_t mysem;
sem_init(&mysem, 0, 0);
sem_post(&mysem);

这个例子中会将 mysem信号量的值加1.

使用sem_post()函数可以在线程或进程之间进行同步,避免竞争条件或死锁的产生。

需要注意的是,使用sem_post()函数增加信号量的值时要保证信号量的值不会超过初始化时的值,否则可能会造成意外的错误。

为什么不能超过初始化的值?
信号量是一种用于控制访问共享资源的同步机制,它通过维护一个整数值来实现资源限制。在初始化信号量时,会设定一个初始值,表示最多可以有多少个线程或进程同时访问共享资源。

如果使用sem_post()函数增加信号量的值时超过了初始化时的值,就意味着允许了超过限制的线程或进程访问共享资源,这可能会导致资源竞争和数据不一致等问题。

因此,在使用信号量时,需要谨慎控制信号量的值,避免超过初始化时的值。

4、sem_getvalue();

sem_getvalue()函数用于获取信号量的当前值,它有两个参数:

sem:指向要获取值的信号量的指针。
sval:指向用于存储当前值的变量的指针。
sem_getvalue()函数成功时返回0,失败返回-1。
例如:

sem_t mysem;
int value;
sem_init(&mysem, 0, 5);
sem_getvalue(&mysem, &value);
printf("value of mysem is %d\n", value);

这个例子中会打印出:value of mysem is 5

当然可以在使用P和V操作之后,使用sem_getvalue()函数来获取当前信号量的值。

另外需要注意的是,在使用信号量前需要对其进行初始化。

5、sem_destroy();

sem_destroy()semaphore.h 头文件中定义的函数。它是用于销毁信号量的函数。

该函数的参数是信号量指针,用于指向需要销毁的信号量。

调用 sem_destroy()函数后,会释放与该信号量相关的所有资源,并将该信号量的值设置为未定义。之后该信号量将不能再被使用。

在使用完信号量后,应该及时调用 sem_destroy() 函数来销毁信号量,以释放系统资源。

sem_destroy()函数用于释放信号量占用的系统资源。它有一个参数:sem,指向要销毁的信号量。

例如:

sem_t mysem;
sem_init(&mysem, 0, 1);
sem_destroy(&mysem);

这个例子中会创建一个叫 mysem的信号量并初始化它的值为1,然后销毁该信号量.

需要注意的是,在调用sem_destroy()之前,需确保不再有线程或进程在等待该信号量。如果有线程或进程在等待该信号量,会产生未定义的结果.

释放完信号量之后不能再使用该信号量,需要重新初始化该信号量.

实例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

sem_t sem; // 定义信号量

void *thread_function(void *arg)
{
    // 等待信号量
    sem_wait(&sem);
    printf("进入线程,已获取信号量\n");
    sleep(3); // 模拟线程执行的操作
    printf("线程执行完毕,释放信号量\n");
    sem_post(&sem); // 释放信号量
    return NULL;
}

int main()
{
    sem_init(&sem, 0, 1);  // 初始化信号量,第一个参数为信号量对象,第二个参数为0表示进程内使用,1表示进程间使用,第三个参数为信号量的初始值
    pthread_t thread1, thread2;
    pthread_create(&thread1, NULL, thread_function, NULL);
    pthread_create(&thread2, NULL, thread_function, NULL);
	// 等待线程结束
	pthread_join(thread1, NULL);
	pthread_join(thread2, NULL);
	printf("所有线程已结束\n");
	sem_destroy(&sem); // 销毁信号量
	return 0;
}

该程序中创建了两个线程,每个线程都在调用sem_wait函数等待信号量,在获取到信号量之后进行相应的操作,最后使用sem_post释放信号量。

结束

如果对你有所帮助点赞支持一下吧。
转载请联系本人。

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Strange_Head

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值