文章目录
在上一篇博客中我们提到多线程共享同一个资源,怎么解决多个线程之间共享同一个共享资源,是多线程编程需要考虑的一个问题!本章将会对此问题做出解答!首先我们先了解一下互斥锁
互斥锁的概念及使用
1、在编程中,用互斥锁来保证共享数据操作的完整性,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量。对互斥量进行上锁以后,其他试图再次对互斥量加锁的线程都会被阻塞直到当前线程释放该互斥锁。我们可以举个简单的例子,可以有助于大家的理解!
试想一下,我们大学宿舍只有一个洗手间,那宿舍四个人怎么解决马桶共享的问题?这就需要锁的机制来解决,马桶就是临界资源,我们进入洗手间(临界区)后,首先上锁;然后用完离开洗手间(临界区)之后,把锁释放供其他人使用。如果有人想去洗手间时发现门锁上了,他也有两种策略:1、在洗手间那里等(阻塞); 2、暂时先离开等会再过来看(非阻塞)。
2、互斥锁的使用
int pthread_mutex_lock(pthread_mutex_t* mutex); //申请锁并上锁(阻塞锁);
int pthread_mutex_trylock(pthread_mutex_t* mutex); //申请锁,并测试上锁(非阻塞锁)
int pthread_mutex_unlock (pthread_mutex_t* mutex); //解锁
int pthread_mutex_destroy (pthread_mutex_t* mutex); //互斥锁使用完之后,将它摧毁释放
互斥锁解决多线程代码示例
上篇博客写了多线程编程,此代码将解决上个博客出现的问题!
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
void *thread_worker1(void *args);
void *thread_worker2(void *args);
//为什么要定义一个结构体那?因为在创建给线程执行函数传参的时候只能传一个参数,而我们要传递共享变量shared_var
//和相应的互斥锁lock,所以需要将他们用struct封装给起来
typedef struct worker_ctx_s
{
int shared_var;
pthread_mutex_t lock;
}worker_ctx_t;
int main (int argc, char **argv)
{
worker_ctx_t worker_ctx;//定义一个结构体变量
pthread_t tid;//定义一个线程
pthread_attr_t thread_attr;//定义线程属性
worker_ctx.shared_var = 1000;
pthread_mutex_init(&worker_ctx.lock,NULL);//初始化互斥锁
if(pthread_attr_init(&thread_attr))//初始化线程
{
printf("pthread_attr_init()failure:%s\n",strerror(errno));
return -1;
}
if(pthread_attr_setstacksize(&thread_attr,120*1024))//设置线程属性栈的大小
{
printf("pthread_attr_setstacksize()failure:%s\n",strerror(errno));
return -2;
}
if(pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED))//设置线程为可分离状态
{
printf("pthread_attr_setdetachstate()failure:%s\n",strerror(errno));
return -3;
}
pthread_create(&tid,&thread_attr,thread_worker1,&worker_ctx);//&tid,用来返回该线程的id,第二个参数是线程的属性,第三个参数是子线程要完成的任务,第四个参数是传给所调用的函数的指针
printf("Thread worker1 tid[%ld]created ok\n",tid);
pthread_create(&tid,&thread_attr,thread_worker2,&worker_ctx);
printf("Thread worker2 tid[%ld]created ok\n",tid);
while(1)
{
printf("main thread shared_var:%d\n",worker_ctx.shared_var);
sleep(10);
}
pthread_mutex_destroy(&worker_ctx.lock);//互斥锁使用完之后,将它摧毁释放
}
void *thread_worker1(void *args)
{
worker_ctx_t *ctx = (worker_ctx_t *)args;
if( !args )
{
printf("%s()get invalid arguments\n", __FUNCTION__);
pthread_exit(NULL);
}
printf("Thread worker1 [%ld]start running..\n",pthread_self());//打印自己的线程id
while(1)
{
pthread_mutex_lock(&ctx->lock);//请求锁并上锁
printf("+++ %s before shared_var++:%d\n", __FUNCTION__,ctx->shared_var);
ctx->shared_var ++;
sleep(2);
printf("+++:%s after sleep shared_var:%d\n", __FUNCTION__,ctx->shared_var);
pthread_mutex_unlock(&ctx->lock);//解锁
sleep(1); //这里都要加上延时,否则一个线程拿到锁之后会一直占有该锁;另外一个线程则不能获取到锁;
}
printf("Thread worker 1 exit...\n");
return NULL;
}
void *thread_worker2(void *args)
{
worker_ctx_t *ctx=(worker_ctx_t *)args;
if(!args)
{
printf("%s()get invalid arguments\n",__FUNCTION__);
pthread_exit(NULL);
}
printf("Thread worker2 [%ld]start running..\n",pthread_self());
while(1)
{
if(0 !=pthread_mutex_trylock(&ctx->lock))//测试锁并上锁
{
continue;
}
printf("--- %s before shared_var++:%d\n", __FUNCTION__,ctx->shared_var);
ctx->shared_var ++;
sleep(2);
printf("---:%s after sleep shared_var:%d\n", __FUNCTION__,ctx->shared_var);
sleep(1);// 加上延时,否则一个线程拿到锁之后会一直占有该锁;另外一个线程则不能获取到锁;
}
printf("Thread worker 2 exit...\n");
return NULL;
}
代码运行结果:
代码分析:可以看出来thread_worker1 在创建后首先开始运行,在开始自加之前值为初始1000,然后让该值自加后休眠2秒后再打印该值就是1001了,不再是1002了,这就是锁的机制!如有错误的地方,还请下方提出,我将进行改正