多线程同步之信号量

64 篇文章 3 订阅

对于多线程程序来说,同步是指在一定的时间内只允许某一个线程访问某个资源 。 而在
此时间内,不允许其他的线程访问该资源。同步资源的方式:互斥锁、条件变量、读写锁、
信号量。
信号量和互斥锁的区别: 互斥锁只允许一个线程进入临界区,而信号量允许多个线程同时进入临界区
信号量。

一、基本原理
信号量和互斥锁的区别:互斥锁只允许一个线程进入临界区,而信号量允许多个线程同时进入临界区。
以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。
在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。

二、API
1、创建信号量
int sem_init(sem_t *sem , int pshared , unsigned int value) ;

sem :指向信号量对象

pshared : 指明信号量的类型。不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享。
  value : 指定信号量值的大小

调用成功返回0
2、sem wait 函数 。
该函数用于以原子操作的方式将信号量的值减 1 。 原子操作就是 ,如果两个线程企图 同

时给一个信号量加 1 或减 l ,它们之间不会互相干扰 , 函数的原型如下:
int sem_wait(sem_t *sem);
调用成功返回0,调用成功返回-1
3、 sem_post 函数 。
该函数用于以原子操作的方式将信号量的值加 1 ,函数的原型如下:
int sem__post (sem_ t *sem);
调用成功返回0,调用成功返回-1
4、sem_destroy 函数
该函数用于对用完的信号量进行清理,函数的原型如下:
int sem_destroy ( sem_t *s em);
成功时返回 0 ,失败时返回- 1 。

#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define CUSTOMER_NUM 10
/* @Scene: 某行业营业厅同时只能服务两个顾客。
 * 有多个顾客到来,每个顾客如果发现服务窗口已满,就等待,
 * 如果有可用的服务窗口,就接受服务。 */
/* 将信号量定义为全局变量,方便多个线程共享 */
sem_t sem;
/* 每个线程要运行的例程 */
void * get_service(void *thread_id)
{
/* 注意:立即保存thread_id的值,因为thread_id是对主线程中循环变量i的引用,它可能马上被修改*/
    int customer_id = *((int *)thread_id);
    if(sem_wait(&sem) == 0) 
    {
        usleep(100); /* service time: 100ms */
        printf("customer %d receive service ...\n", customer_id);
        sem_post(&sem);
    }
     pthread_exit((void*)0);
}

int main(int argc, char *argv[])
{
    /*初始化信号量,初始值为2,表示有两个顾客可以同时接收服务 */
    sem_init(&sem,0,2);
    
    /*为每个顾客定义一个线程id*/
    pthread_t customers[CUSTOMER_NUM];
    
    int i, iRet;
    /* 为每个顾客生成一个线程 */
    for(i = 0; i < CUSTOMER_NUM; i++)
    {
        int customer_id = i;
        iRet = pthread_create(&customers[i], NULL, get_service, &customer_id);
        if(iRet){
            perror("pthread_create");
            return iRet;
        }
        else{
            printf("Customer %d arrived.\n", i);
        }
        usleep(10);
    }

    /* 等待所有顾客的线程结束 */
    /* 注意:这地方不能再用i做循环变量,因为可能线程中正在访问i的值 */

    int j;
    for(j = 0; j < CUSTOMER_NUM; j++)
    {
        pthread_join(customers[j], NULL);
    }
    /*销毁信号量*/
    sem_destroy(&sem);
    return 0;
}
//运行环境Ununtu
把文件命名为Thread.cpp
编译:g++ -o Thread Thread.cpp -lpthread
运行./Thread
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值