多进程/线程的同步与互斥实现

您所在的位置:网站首页 java线程互斥的几种方式 多进程/线程的同步与互斥实现

多进程/线程的同步与互斥实现

2023-11-24 23:59| 来源: 网络整理| 查看: 265

多线程同步与互斥

上一篇在这 在上一次的学习中,我们了解到了进程间的6种通信机制,其中信号量是主要用于于实现进程间的同步与互斥,它使得共享资源在某一时刻只能被一个进程访问,防止了多进程竞争共享资源而造成资源混乱。

🚀在这一次的学习中,我们再来了解关于共享资源在多线程环境中存在的问题。

竞争与协作(互斥与同步)

我们知道,线程就是进程中的一条执行流程。如果一个进程中只有一个执行流程,那么它是单线程进程;如果一个进程中有多个执行流程那么就是多线程进程。线程是调度的基本单位,进程是资源分配的基本单位。

所以,线程之间是可以共享进程的资源,如代码段、堆空间、数据段、打开的文件等资源,但是每个线程都有自己独立的栈空间。

💣因此,随之出现了一个问题,就是如果多个线程竞争共享资源,不采取一定的措施就会造成共享数据的混乱。

具体例子:创建两个线程,他们分别对共享变量i自增1执行10000次。

#include // I/O流对象 std::cout输出一些内容到控制台 #include // 多线程编程头文件 std::thread创建一个线程 //共享数据 int i = 0; //线程函数 对变量i进行自增操作 void test() { int num = 10000; for(int n = 0; n < num; n++) { i += 1; } } int main(void) { //控制台输出 主线程操作 std::cout int old = *old_ptr; *old_ptr = new; return old; } typedef struct lock_t { int flag; //表示锁的状态 } lock_t; void init(lock_t *lock) { lock->flag = 0; //初始化锁的状态为解锁 } void lock(lock_t *lock) { //TestAndSet返回值等于1则其他线程在临界区中 当前线程阻塞 while(TestAndSet(&lock->flag, 1) == 1); } void unlock(lock_t *lock) { lock->flag = 0;//解锁操作 } 场景一: 假设一个线程在运行,调用lock(),没有其他线程持有锁,所以flag是0。当调用TestAndSet(flag,1)方法时,返回0,则线程跳出while循环,获取锁。同时,将flag设置为1,标志锁已经被占用。当线程离开临界区,调用unlock()将flag清理为0。 场景二: 当一个线程已经持有锁(flag为1)。本线程调用lock(),然后调用 TestAndSet(flag,1),此时返回1。只要另一个线程一直持有锁则一直返回1,本线程会一直忙等。 当flag终于改为0,本线程调用 TestAndSet()返回0并原子地设置为1,从而获得锁进入临界区。

当获取不到锁时,线程就会一直while循环,不做任何事情,所以被称为 “ 忙等待锁 ” ,也被称为 “ 自旋锁 ” 。

自旋锁是最简单的一种锁,一直自旋,利用CPU周期直到锁可用。在单处理器上,需要抢占式的调度器(即不断通过时钟中断一个线程,运行其他线程)。否则,自旋锁在单CPU上无法使用,因为一个自旋锁不会放弃CPU。

📔无等待锁

传统的互斥锁在资源被占用时会导致请求锁的线程进入阻塞状态,等待资源的释放。 这种阻塞导致其他线程无法继续执行,从而影响了系统的并发性能。为了解决这个问题,无等待锁被引入。

无等待锁就是在上述情况下获取不到锁的时候不用自旋,把当前线程放入到锁的等待队列,然后执行调度程序,把CPU让给其他线程执行。

无等待锁可以通过一些特殊的算法和技术实现,可以确保当多个线程同时请求锁时,至少有一个线程能够成功获取锁并继续执行,而其他线程会继续尝试获取锁,而不是阻塞等待。

信号量

信号量在之前的学习中已经提到过,具体概念在上一篇中。

信号量是操作系统提供的一种协调共享资源访问的方法。

通常信号量表示资源的数量,对应的变量是一个整型变量(sem)。

还有两个原子操作的系统调用函数用来控制信号量:

P操作:将sem减1,相减后如果sem s->sem = sem; queue_init(s->q); } //P操作 void P(sem_t *s) { s->sem--; if(s->sem s->sem++; if(s->sem while(TRUE) { //肚子饿 V(s1);//叫妈妈做饭 P(s2);//等待饭做好 } } //妈妈线程 void mom() { while(TRUE) { P(s1);//询问是否需要做饭 //做饭 V(s2);//做完饭 } }

最后的通过信号量实现线程同步的描述还不到位,在我功力精进后再来好好完善一下。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3