线程的同步与互斥
线程是一个存在进程中的一个执行控制流,因为线程没有进程的独立性,在进程内部线程的大部分资源数据都是共享的,所以在使用的过程中就需要考虑到线程的安全和数据的可靠。不能因为线程之间资源的竞争而导致数据发生错乱,也不能因为有些线程因为调度器长时间没有调度从而导致饥饿问题。所以在线程中也有了同步与互斥,这里用 “也” 是因为进程中也有同步与互斥,今天来了解线程中的同步与互斥。
互斥量
我们为什么要有互斥量
首先,一个进程中的多个线程因为同处于一个虚拟地址空间中,所以相互之间大部分数据是共享的,从而在线程竞争中出现数据错乱的情况,我们来举例子来看一下
首先我们采用多个线程去竞争着去修改count的数据,我们定义初始的count为100,让其减少为0就可以了,我们看看会有什么结果。
如果对线程不了解或者相关的创建API点击线程概念、线程创建、等待、退出
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define num 3 //我们用3个线程
int count = 100;
void* MyFun(void* arg) //线程入口函数
{
int j = (int)arg;
while (ticket >= 0)
{
usleep(1000);
printf("thread %d count %d\n", j, count);
count--;
}
return NULL;
}
int main()
{
pthread_t th[num];
int i = 0;
for (;i < num; ++i)
{
// 创建线程
int ret = pthread_create(&th[i], NULL, MyFun, (void*)i);
if (ret != 0)
{
perror("pthread_create error\n");
exit(1);
}
}
i = 0;
for (; i < num; ++i)
{
// 等待线程,释放资源
pthread_join(th[i], NULL);
}
return 0;
}
我们先看看结果
看到这个结果,如果仔细看代码就会发现,我们写的是代码count到0就退出,但是为什么会出现到-2呢?这里我们就解释一下
首先线程之间资源共享,所以随着cpu的调度,如果你是多核计算机,线程是可以同时访问一个共享资源,这个时候就会发生:
这只是其中的一种情况,还有可能在内存读到寄存器中的时候被切换掉等,就出现了数据错误的情况。
所以我们要加上互斥锁,让互斥的访问临界资源。
我们修改我们的代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define num 3
// 互斥锁
pthread_mutex_t mutxe;
int ticket = 100;
void* MyFun(void* arg)
{
long j = (long)arg;
while (1)
{
usleep(1000);
pthread_mutex_lock(&mutxe); // 加锁
if (ticket > 0)
{
printf("thread %lu ticket %d\n", j, ticket);
ticket--;
pthread_mutex_unlock(&mutxe); // 解锁