Linux多线程的同步-----信号量和互斥锁

前面两篇给基本概念讲过了,大家有兴趣的可以去看一下:
Linux多线程_神厨小福贵!的博客-CSDN博客进程和线程的区别有哪些呢?进程是资源分配的最小单位,线程是CPU调度的最小单位进程有自己的独立地址空间,线程共享进程中的地址空间进程的创建消耗资源大,线程的创建相对较小进程的切换开销大,线程的切换开销相对较小进程:程序执行的过程叫进程。线程:进程内部的一条执行序列或执行路径,一个进程可以包含多条线程(多线程)!每个进程最少有一个线程,例如下面代码:#include int main(){ return 0;} ...https://blog.csdn.net/qq_45829112/article/details/121458560Linux多线程的进阶理解_神厨小福贵!的博客-CSDN博客首先来看在Linux中如何实现多线程的,下面是《Linux内核设计与实现第三版》中扫描页的截图:这段话我冒昧的解析一下,如有不当,欢迎指出,大家共同进步!在Linux中线程和进程没有任何区别(站在内核角度来看),每个线程属于自己的task_struct,task_struct相当于在进程中的PCB(进程描述符),每创建一个新的进程就有一个新的进程描述符,在内核中线程看起来就是普通的进程,但是这个进程和它的主线程(在内核看来就是主进程)共享一块内存地址,同一个进程描述符!下面来看一段代码.https://blog.csdn.net/qq_45829112/article/details/121522914

下面来说一下Linux多线程中使用信号量和互斥锁对多线程进行同步!

先来看一下下面的一段代码来了解为什么需要对进程进行同步:

#include
#include
#include
#include
#include //多线程的创建  等待  退出所需的头文件
 
int g_index = 1;

void* fun(void* arg)
{
    for(int i = 0 ; i < 1000 ; i++)
    {
        printf(" g_index = %d \n",g_index++);
    }
}

int main()
{
    pthread_t id[5];
    for(int i = 0 ; i < 5 ; i++)
    {
        pthread_create(&id[i],NULL,fun,NULL);
    }
    for(int i = 0 ; i < 5  ; i++)
    {
        pthread_join(id[i],NULL);
    }

    exit(0);
 
}

如上代码所示,该代码的初衷是想由主线程创建五个子线程来共同对全局变量g_index进行++的操作,理想中打印出来的结果应该是1 2 3  ......  5000

那么具体结果是如何呢,下面我们来看一下代码运行的结果:

这是第一次运行::

Linux多线程的同步-----信号量和互斥锁_第1张图片

 这是第二次运行:

Linux多线程的同步-----信号量和互斥锁_第2张图片

 大家可以看看,仅仅是两次的运行,结果就大不相同,这只是两次的结果,如果多运行几次,那么结果可能千变万化。

我们先来说一下出现这种情况的原因是什么,请看下图:

Linux多线程的同步-----信号量和互斥锁_第3张图片

 那么如何解决这种情况呢,信号量和互斥锁

下面来看信号量:

先来看包含他们的头文件:#include  

信号量的初始化int sem_init(sem_t *sem, int pshared, unsigned int value); 

Linux多线程的同步-----信号量和互斥锁_第4张图片

 第一个参数是信号量的地址;

第二个参数是释放需要两线程之间共享,这里我们用不到,给个0就好

第三个参数是信号量的初始值

信号量的p(对信号进行-1的操作)操作:int sem_wait(sem_t *sem); 

信号量的v(对信号量进+1操作)操作:int sem_post(sem_t *sem); 

参数就是信号量的地址

信号量的销毁:int sem_destroy(sem_t *sem); 

那么对于这道题来说,想要让五个子线程打印5000个有序的数来说,需要定义多少个信号量呢?大家好好想想,没思路的话,可以去看看这篇博客:Linux编程题:信号量同步三进程依次打印若干次ABC_神厨小福贵!的博客-CSDN博客

大家是不是以为定义5个信号量,来追着下一个信号量的尾巴,对它进行操作,然后打印吗?

错了(也不是完全错了),上面那种五个信号量适用于进程间的,而在线程中,他们是并发执行的,你要是搞5个信号量的,就是规定了每个线程的打印顺序,完全没必要,我们现在完全不关心谁先打印数字(谁先打印都无所谓的),我们关心的只是多个线程中同时只有一个能进行打印,所以一个信号量足够了,下面来看代码:

#include
#include
#include
#include
#include 
#include  //信号量操作所需的头文件
 
sem_t semid;    //定义信号量
int g_index = 1;

void* fun(void* arg)
{
    for(int i = 0 ; i < 1000 ; i++)
    {
        sem_wait(&semid);   //在g_index++之前进行减一操作,使得其他的线程堵塞
        printf(" g_index = %d \n",g_index++);
        sem_post(&semid);   //在g_index++之后进行加一操作,使得其他的线程得以正常运行
    }
}

int main()
{
    sem_init(&sem,0,1);  //将信号量初始值给1
    pthread_t id[5];
    for(int i = 0 ; i < 5 ; i++)
    {
        pthread_create(&id[i],NULL,fun,NULL);
    }
    for(int i = 0 ; i < 5  ; i++)
    {
        pthread_join(id[i],NULL);
    }

    sem_destroy(&semid); //信号量的销毁函数
    exit(0);
 
}

这样的话,我们来看一下运行结果!

Linux多线程的同步-----信号量和互斥锁_第5张图片

 这样的话,就让多线程并发执行进行同步!

下面再来看看互斥锁:

头文件就是线程创建函数的头文件:#include  

线程同步指的是当一个线程在对某个临界资源进行操作时,其他线程都不可以对这个资源进行操作,直到该线程完成操作, 其他线程才能操作,也就是协同步调,让线程按预定的先后次序进行运行。

互斥锁可以理解为就是在商场试衣间里面,你进去之后给试衣间上锁,然后其他人就必须等你解锁之后才可以正常使用这个试衣间,你在使用的时候,其他人只能阻塞(等你使用完)!

互斥锁的初始化:

int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr); 

第一个参数是互斥锁的饿地址

第二个参数是互斥锁的属性,一般置为NULL

互斥锁的上锁:int pthread_mutex_lock(pthread_mutex_t *mutex); 

互斥锁的解锁:int pthread_mutex_unlock(pthread_mutex_t *mutex); 

互斥锁的销毁:int pthread_mutex_destroy(pthread_mutex_t *mutex); 

参数都是互斥锁的地址

下面来看代码:

#include
#include
#include
#include
#include 
 
int g_index = 1;
pthread_mutex_t mutex;   //互斥锁的定义

void* fun(void* arg)
{
    for(int i = 0 ; i < 1000 ; i++)
    {
        pthread_mutex_lock(&mutex);    //互斥锁的上锁 
        printf(" g_index = %d \n",g_index++);
        pthread_mutex_unlock(&mutex);   //互斥锁的解锁
    }
}

int main()
{
    pthread_mutex_init(&mutex,NULL);   //互斥锁的初始化
    pthread_t id[5];
    for(int i = 0 ; i < 5 ; i++)
    {
        pthread_create(&id[i],NULL,fun,NULL);
    }
    for(int i = 0 ; i < 5  ; i++)
    {
        pthread_join(id[i],NULL);
    }

    pthread_mutex_destroy(&mutex);
    exit(0);
 
}

然后代码运行结果和上述的信号量一毛一样:

Linux多线程的同步-----信号量和互斥锁_第6张图片

信号量和互斥锁的代码不难,难的是理解这种思想,因为这是线程,所以在定义信号量的时候,定义一个就够了,因为谁打印出那个数字,我不在乎,五个子线程谁抢到了谁就打印,但是每次只能有一个子线程在打印,互斥锁也是如此,每次只能一个线程去打印,理解了思想,这就可以了!

“累的时候,可以休息,但是弓出没有回头路,坚持走下去!”

你可能感兴趣的:(Linux,Linux,多线程,信号量,互斥锁)