扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
线程的同步与互斥
创新互联专注于企业营销型网站建设、网站重做改版、三原网站定制设计、自适应品牌网站建设、H5建站、成都商城网站开发、集团公司官网建设、外贸网站建设、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为三原等各大城市提供网站开发制作服务。多个线程同时访问共享数据时可能会发生冲突,比如两个线程同时把一个全局变量加1,结果可能不是我们所期待的:
我们看这段代码的执行结果:
#include
#include
#include
static int g_count=0;
void *thread(void *arg)
{
int index=0;
int tmp=0;
while(index++<5000)
{
tmp=g_count;
printf("this is thread %d,count is :%d\n",(int)arg,tmp);
g_count=tmp+1;
}
}
int main()
{
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,thread,(void*)1);
pthread_create(&tid2,NULL,thread,(void*)2);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
printf("the final value is %d\n",g_count);
return 0;
}
我们看它的执行结果:
我们创建了两个线程,各自把全局变量g_count加了5000次,结果理论上应该是10000,但其实不然,每次运行的结果都不一样,证明访问冲突了。为了解决这个问题,我们需引入互斥锁。获得锁的线程可以完成“读--修改--写”的操作,然后释放锁给其他线程,没有获得锁的线程只能等待,而不能访问共享数据,这样“读--修改--写”散步操作就成了原子操作,要么都执行,要么都不执行,不会执行到中间而被打断,这样就如我们所期待的了。
pthread_mutex_init函数对mutex做初始化,它可以被pthread_mutex_destroy销毁。如果mutex变量是静态分配的,也可以用宏定义PTHREAD_MUTEX_INITIALIZER来初始化,相当于pthread_mutex_init初始化并且attr参数为NULL。
加锁和解锁所需函数:
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
成功返回0,失败返回错误号。
一个线程可以调用int pthread_mutex_lock获得mutex,如果这时候另一个线程已经调用int pthread_mutex_lock获得了该mutex,则当前线程需要挂起等待,直到另一个线程调用pthread_mutex_unlock释放mutex,当前线程被唤醒,才能获得该mutex并继续执行。
如果一个线程既想获得锁,又不想挂起等待,可以调用 pthread_mutex_trylock,如果mutex已经被另一个线程获得,则这个函数会返回EBUSY,而不会使线程挂起等待。
知道这些的话,我们重新修改以上代码:
#include
#include
#include
static int g_count=0;
pthread_mutex_t mutex_lock=PTHREAD_MUTEX_INITIALIZER;
void *thread(void *arg)
{
int index=0;
int tmp=0;
while(index++<5000)
{
pthread_mutex_lock(&mutex_lock);
tmp=g_count;
printf("this is thread %d,count is :%d\n",(int)arg,tmp);
g_count=tmp+1;
pthread_mutex_unlock(&mutex_lock);
}
}
int main()
{
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,thread,(void*)1);
pthread_create(&tid2,NULL,thread,(void*)2);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
printf("the final value is %d\n",g_count);
return 0;
}
运行结果如下:
我们可以看到,经过我们加锁后,最后value的值是我们所期待的10000,加锁成功,成功实现了两个线程的互斥运行。
死锁产生的原因及四个必要条件
所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,他们都将无法再向前推进。
产生死锁的主要原因有:
1.系统资源不足;
2.进程运行推进的顺序不合适;
3.资源分配不当等;
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就降低,否则,就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
1.互斥条件:一个资源每次只能被一个进程使用;
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;
3.不剥夺条件:进程已获得的资源,在使用完之前,不能强行剥夺;
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系;
以上是产生死锁的四个必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
处理死锁的基本方法:
1.预防死锁:
该方法是通过设置某些限制条件,去破坏产生死锁四个必要条件中的一个或几个条件,来预防发生死锁。
2.避免死锁
不需事先采取各种限制措施去破坏产生死锁的四个必要条件,而是在资源的动态分配过程中,用某种方法去防止系统进入不安全状态,从而避免发生死锁。
3.检测死锁
这种方法不需事先采取任何限制措施,也不必检查系统是否已经进入不安全区,而是允许系统在运行过程中发生死锁。但可以通过系统所设置的检测机构,及时的检测死锁的发生,并精确的确定与死锁有关的进程资源,然后采取适当措施,从系统中将已发生的死锁清除掉。
4.解除死锁
这是与检测死锁相配套的一种措施。当检测到发生死锁时,需将进程从死锁状态中解脱出来。常用的实施方法是撤消或挂起一些进程,以便回收一些资源,再将这些资源分配给已处于阻塞状态的进程,使之转为就绪状态,一边继续运行。
死锁的解除与预防:
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以大程度的避免,预防和解除死锁。所以在系统设计,进程调度等方面注意如何不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占用系统资源。此外,也要防止进程在处于等待状态的情况下占用资源。因此,对资源的分配要给与合理的规划。
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
Copyright © 2002-2023 www.kswjz.com 快上网建站品牌 QQ:244261566 版权所有 备案号:蜀ICP备19037934号
微信二维码
移动版官网