Linux系统编程-(pthread)线程通信(信号量)

简介: 信号量的运用环境与互斥锁一样,但是信号量比互斥锁增加灵活,互斥锁只有两个状态(开锁和解锁),而信号量本质上是一个计数器,它内部有一个变量计数信号值,可以保护一个资源可以同时被1个或者2个或者3个线程同时使用,如果信号量的值只是设置1(状态只有0和1),那么和互斥锁就是一样的功能。

1. 信号量介绍

信号量的运用环境与互斥锁一样,但是信号量比互斥锁增加灵活,互斥锁只有两个状态(开锁和解锁),而信号量本质上是一个计数器,它内部有一个变量计数信号值,可以保护一个资源可以同时被1个或者2个或者3个线程同时使用,如果信号量的值只是设置1(状态只有0和1),那么和互斥锁就是一样的功能。

总结

  1. 信号量也主要是用来保护共享资源(信号量也属于临界资源),使得资源在一个时刻只有一个线程或者多个线程独享。
  2. 信号量是一种特殊的变量,访问具有原子性, 用于解决进程或线程间共享资源引发的同步问题。
  3. 信号量就是一个计数变量,内部本身就是一个变量。只不过这个变量具有原子性。
  4. 信号量经常用来保护临界区资源、实现资源同步。
  5. 如果信号量只有2个值,0和1,就称为二值信号量==互斥锁。

信号量和互斥锁(mutex)的区别:互斥锁只允许一个线程进入临界区,而信号量允许多个线程同时进入临界区,要使用信号量同步,需要包含头文件semaphore.h

2. 信号量实现接口函数

2.1 初始化信号量

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value); //通常 pshared 为 0.表示线程间

sem_init是创建信号量的 API,其中 value 为信号量的初值,pshared 表示是否为多进程共享而不仅仅是用于一个进程之间的多线程共享。

如果pshared的值为0,那么信号量在进程的线程之间共享,并且应位于所有线程可见的某个地址(例如,全局变量)能够,或在堆上动态分配的变量),如果pshared不为零,那么信号量在进程之间共享,信号量的值就位于共享内存区域。

2.2 注销信号量

int sem_destroy(sem_t * sem);

注销信号量时,必须保证被注销的信号量 sem没有线程在等待该信号量,否则会返回-1,且置 errno 为 EBUSY。正常返回0。

2.3 释放信号量

int sem_post(sem_t * sem); //相当于解锁

释放信号量操作将信号量值原子地加 1,表示增加一个可访问的资源。只有信号量值大于 0,才能访问公共资源。主要用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞。

2.4 等待信号量

int sem_wait(sem_t * sem);     //相当于加锁
int sem_trywait(sem_t * sem);   //不阻塞

sem_wait()用于阻塞等待信号量(获取信号量),主要被用来阻塞当前线程直到信号量 sem 的值大于 0,得到信号量之后,信号量的值会减一。

2.5 获取当前的信号量值

int sem_getvalue(sem_t * sem, int * sval);

读取sem中的信号量计数,存于*sval 中,并返回 0。

3. 案例代码: 信号量框架运用模型

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

sem_t sem; //信号量结构

int data;
/*
线程工作函数
*/
void *thread_work_func(void *dev)
{
    while(1)
    {
        sem_wait(&sem); //获取信号量. 当信号量的值大于0才能获取成功. --
        printf("data=%d\n",data);
        sem_post(&sem); //释放信号量.  ++
        sleep(1);
    }
}

/*
线程工作函数
*/
void *thread_work_func2(void *dev)
{
    while(1)
    {
        sem_wait(&sem); //获取信号量. 当信号量的值大于0才能获取成功. --
        data++;
        sem_post(&sem); //释放信号量.  ++
        sleep(1);
    }
}

int main(int argc,char **argv)
{   
    //初始化信号量
    sem_init(&sem,0,1);

    /*1. 创建子线程1*/
    pthread_t thread_id;
    if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0)
    {
        printf("子线程1创建失败.\n");
        return -1;
    }
    /*2. 创建子线程2*/
    pthread_t thread_id2;
    if(pthread_create(&thread_id2,NULL,thread_work_func2,NULL)!=0)
    {
        printf("子线程2创建失败.\n");
        return -1;
    }

    /*3. 等待线程的介绍*/
    pthread_join(thread_id,NULL);
    pthread_join(thread_id2,NULL);

    //销毁信号量
    sem_destroy(&sem);
    return 0;
}
目录
相关文章
|
21天前
|
存储 缓存 监控
Linux缓存管理:如何安全地清理系统缓存
在Linux系统中,内存管理至关重要。本文详细介绍了如何安全地清理系统缓存,特别是通过使用`/proc/sys/vm/drop_caches`接口。内容包括清理缓存的原因、步骤、注意事项和最佳实践,帮助你在必要时优化系统性能。
158 78
|
25天前
|
Linux Shell 网络安全
Kali Linux系统Metasploit框架利用 HTA 文件进行渗透测试实验
本指南介绍如何利用 HTA 文件和 Metasploit 框架进行渗透测试。通过创建反向 shell、生成 HTA 文件、设置 HTTP 服务器和发送文件,最终实现对目标系统的控制。适用于教育目的,需合法授权。
56 9
Kali Linux系统Metasploit框架利用 HTA 文件进行渗透测试实验
|
21天前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
89 13
|
21天前
|
Ubuntu Linux C++
Win10系统上直接使用linux子系统教程(仅需五步!超简单,快速上手)
本文介绍了如何在Windows 10上安装并使用Linux子系统。首先,通过应用商店安装Windows Terminal和Linux系统(如Ubuntu)。接着,在控制面板中启用“适用于Linux的Windows子系统”并重启电脑。最后,在Windows Terminal中选择安装的Linux系统即可开始使用。文中还提供了注意事项和进一步配置的链接。
40 0
|
3月前
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解
|
7月前
|
API
linux---线程互斥锁总结及代码实现
linux---线程互斥锁总结及代码实现
|
6月前
|
安全 算法 Linux
【Linux】线程安全——补充|互斥、锁|同步、条件变量(下)
【Linux】线程安全——补充|互斥、锁|同步、条件变量(下)
58 0
|
6月前
|
存储 安全 Linux
【Linux】线程安全——补充|互斥、锁|同步、条件变量(上)
【Linux】线程安全——补充|互斥、锁|同步、条件变量(上)
64 0
|
8月前
|
安全 Linux 调度
【linux线程(二)】线程互斥与线程同步
【linux线程(二)】线程互斥与线程同步
|
8月前
|
安全 算法 Linux
【Linux 系统】多线程(线程控制、线程互斥与同步、互斥量与条件变量)-- 详解(下)
【Linux 系统】多线程(线程控制、线程互斥与同步、互斥量与条件变量)-- 详解(下)