线程并发——锁(超简单)

  一、锁(互斥锁)

        什么是互斥锁呢,我给大家举个例子,我们可以想象成是车站的座位,然后把线程比喻成一个人,你进车站候车的时候,你就要先找到没有人的座位,然后坐下去(表示你正在使用),这样其他的人(其他的线程)就无法再使用这个座位了,如果想要使用该座位就需要你站起来,别人才可以使用。

并发:同时发生

      在生活中,可能会有多个执行单元,同时访问同一个资源。比如座位。使用锁(互斥锁)来保护资源

互斥锁:一个时刻值允许一个执行单元访问共享资源

1.定义并初始化一把锁

pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;

2.访问共享资源前

pthread_mutex_lock(pthread_mutex_t *mutex);

该函数,如果发现锁 是开的,直接关闭该锁,然后继续执行....

如果发现 锁是 关的,   该函数 会让线程 阻塞/睡眠,等待别人解锁唤醒...............................

直到对方开锁.... ...获取锁,关锁..访问...

3.访问完毕解锁

pthread_mutex_unlock(pthread_mutex_t *mutex);

可能会去唤醒等待的线程........

实现代码: 

#include <stdio.h>

#include <string.h>

#include <pthread.h>

#include <unistd.h>



struct msg_struct {

int aa;

int bb;

char des[32];

};



pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;

struct msg_struct data;


void *thread_write(void *argc)

{

int m=1;

while(1){


pthread_mutex_lock(&mylock);
m++;
data.aa=m*11;usleep(1000*1000); 
data.bb=m*111; usleep(1000*1000); 

//if(发现错误){  pthread_exit(); }   结果是没有解锁,然后 对方会被卡死.

strcpy(data.des,"hello,I am writer");
pthread_mutex_unlock(&mylock);
usleep(1000*300);
}
return NULL;

}

void *thread_read(void *argc)

{

while(1){

pthread_mutex_lock(&mylock);

printf("read aa=%d  bb=%d\n",data.aa,data.bb);

pthread_mutex_unlock(&mylock);

usleep(300);

}

return NULL;

}

int main(int argc,char **argv)

{

pthread_t rtid,wtid;

pthread_create(&wtid,NULL,thread_write,NULL );

pthread_detach(wtid);

pthread_create(&rtid,NULL,thread_read,NULL );

pthread_detach(rtid);



while(1){

printf("I am main thread\n");

sleep(5);

}

return 0;

}

二、死锁

1. 某个线程加锁之后忘了解锁,另一个线程 被卡死。

2. 如果需要同时访问多个共享资源,即需要同时获取多把锁。

        见图,解决之道:要求所有执行单元必须顺序访问

三、 线程的条件变量: 线程通知 

        有时候线程需要等待 某个事件/数据的到来,然后处理,处理完毕后继续等待。线程分为提交者,和消费者

1.消费者线程

while(1){

        在##指定位置##睡眠等待数据(等待被唤醒) xx_wait()

        处理数据

}

2.提交者线程

while(1){

        提交数据

        发送通知,去##指定位置##唤醒 xx_signal();

}

实现代码:

#include <stdio.h>
#include <pthread.h>

struct msg_struct {

int val1;

int val2;

int result;

char des[32];

};


int data_flags =0 ; //0-无数据  1-有数据

struct msg_struct data;


pthread_mutex_t mutex_cond; //保护条件变量的锁, 因为两个线程可能同时访问它,造成并发问题

pthread_cond_t wait_cond; //等待者线程在这里睡眠, 提交者线程去这里唤醒睡眠的线程

// 床

void *wait_thread_fun(void *args)

{

while(1){


    if(data_flags == 0){


/*

睡眠等待被唤醒,线程卡死这里

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

cond,线程在 cond这里睡眠,等待被唤醒.

*/


pthread_mutex_lock(&mutex_cond);

pthread_cond_wait(&wait_cond,&mutex_cond );


/*

wait线程持有了锁,然后 去睡眠去了...... 问题来了,submit线程这时候就会被卡住.....

pthread_cond_wait()

{

    ...要去睡眠了,睡眠之前...释放锁...
    
    睡眠中.....,等待被唤醒..

    ----被唤醒...,  再次上锁..

}
*/




/*线程已经被唤醒了....*/

pthread_mutex_unlock(&mutex_cond);

}

data.result = data.val1+data.val2;

printf("wait thread got val1=%d val2=%d,result=%d\n",\

data.val1,data.val2,data.result);



data_flags = 0; //表示我已经处理完毕了数据.....

}

return NULL;

}


void *submit_thread_fun(void *args)

{

int m=234;

while(1){

sleep(3);

m+=10;

data.val1 = m*10;

data.val2 = m+111;

data_flags = 1;

/*

去指定位置 唤醒所有等待的 线程



int pthread_cond_signal(pthread_cond_t *cond);

cond: 条件变量, 等待者线程 在这里睡眠, 提交者线程去这里唤醒睡眠的线程.

返回值: 0-success, 失败 错误码

*/

pthread_mutex_lock(&mutex_cond);

int ret = pthread_cond_signal(&wait_cond);

pthread_mutex_unlock(&mutex_cond);

    if(ret){

    printf("signal err %s\n",strerror(ret)  );

    return NULL;

    }

}

return NULL;

}

int main(void)

{

pthread_t wait_tid;

pthread_t submit_tid;

pthread_create(&wait_tid, NULL,wait_thread_fun,NULL);

pthread_create(&submit_tid, NULL,submit_thread_fun,NULL);

pthread_detach(wait_tid  );

pthread_detach(submit_tid);


while(1){

    printf("I am main \n");

    sleep(5);

    }

return 0;

}
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春风从不入睡、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值