【线程同步1】使用信号量实现线程同步


在之前的博文中有讨论过如何使用信号量实现进程同步(【进程同步】使用信号量实现进程同步(附C++实现代码)),该文中详解了同步的概念以及信号量相关函数的具体使用和实验举例,今天我们来学习如何使用信号量实现线程同步。

信号量

信号量是一个与队列有关的整形变量,可以将它想象为一个数后面拖着一条排队的队列。如图所示:

在这里插入图片描述

其中信号量值代表:

  • 该值大于0,当前有n个可用资源;
  • 该值等于0,当前可用资源为0;
  • 该值小于0,此时有n个进程在等待资源

信号量实现伪代码:

struct semaphone {
    int count;
    queueType queue;
};
void semWait(semaphore s){
    s.count--;
    if(s.count < 0){
		// 进程排队
		// 中断这一进程
	}
}
void semSignal(semaphore s){
	s.count++;
	if(s.count <= 0){
		// 将队列中第一个进程移除队列
		// 该进程为就绪状态
	}
}

其中的semWait可以理解为申请资源,P操作
其中的semSignal为理解为资源,V操作

当固定了可共享资源的数目之后,每当某个线程使用该资源,就执行P操作,若信号量大于0,则信号量数目减一且该线程继续执行;否则,该信号量数目减一且将该线程放入等待资源队列中,停止运行该线程。

具体关于信号量的函数在进程使用信号量实现同步的文章中已经详解过了,故而本文只摘取关于信号量的函数定义总结,具体关于该信号量函数的使用详解,可以翻看我在本博文开头提到的(【进程同步】使用信号量实现进程同步(附C++实现代码))中进行查看。

信号量函数总结

命名信号量相关函数

操作函数定义
创建sem_t *sem_open(const char *name, int oflag, mode_t mode,unsigned int value)
删除int sem_unlink(const char *name)
打开sem_t *sem_open(const char *name, int oflag)
关闭int sem_close(sem_t *sem)
挂出int sem_post(sem_t *sem)
等待int sem_wait(sem_t *sem)
尝试等待int sem_trywait(sem_t *sem)
获取信号量的值int sem_getvalue(sem_t *sem, int *sval)

匿名信号量相关函数

匿名信号量可以用于同一个进程中的线程使用。

操作函数
初始化int sem_init (sem_t *sem , int pshared, unsigned int value)
销毁int sem_destroy(sem_t *sem)
挂出int sem_post(sem_t *sem)
等待int sem_wait(sem_t *sem)
尝试等待int sem_trywait(sem_t *sem)
获取信号量的值int sem_getvalue(sem_t *sem, int *sval)

使用信号量实现进程同步

运行代码如下:

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>

using namespace std;

void* func(void* arg){
    for(int i=0; i<10; ++i){
        usleep(100);
        cout << pthread_self() << ":before" << endl;
        usleep(100);
        cout << pthread_self() <<  ":exit" << endl;
    }
    pthread_exit(new int(2));
}

int main(){
    pthread_t tid;
    pthread_create(&tid, NULL, func, NULL);

    usleep(500); // 等待子进程跑起来

    func(NULL);
    pthread_join(tid, NULL);
}

运行结果如下:

在这里插入图片描述
会发现线程运行顺序是混乱的,我们增添信号量,使得两个线程按照一定顺序执行。

运行代码如下:

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>

using namespace std;

void* func(void* arg){
    sem_t* p = (sem_t*)arg;
    for(int i=0; i<10; ++i){
        usleep(100);
        sem_wait(p);
        cout << pthread_self() << ":before" << endl;
        usleep(100);
        cout << pthread_self() <<  ":exit" << endl;
        sem_post(p);
    }
}

int main(){
    sem_t sem; // 对线程而言是共享的,所以这个信号量可以不是用共享内存定sem_init(&sem, 0, 1);
    pthread_t tid;
    pthread_create(&tid, NULL, func, &sem);

    usleep(500); // 等待子进程跑起来

    func(&sem);
    pthread_join(tid, NULL);
    sem_destroy(&sem);
}

执行部分结果如下:

在这里插入图片描述
两个线程执行顺序显然是有序的,只有一个线程可以进入func函数的关键代码(sem_wait至sem_post部分),从而实现了线程同步。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值