相关概念
共享资源
临界资源:多线程执⾏流被保护的共享的资源就叫做临界资源
临界区:每个线程内部,访问临界资源的 代码,就叫做临界区
互斥:任何时刻,互斥保证有且只有⼀个执⾏流进⼊临界区,访问临界资源,通常对临界资源起 保护作⽤
原⼦性:不会被任何调度机制打断的操作,该操作只有两态,要么完成, 要么未完成
互斥量mutex
引入原因
⼤部分情况,线程使⽤的数据都是局部变量,变量的地址空间在线程栈空间内,这种情况,变量归属单个线程,其他线程⽆法获得这种变量。
但有时候,很多变量都需要在线程间共享,这样的变量称为共享变量,可以通过数据的共享,完 成线程之间的交互。
多个线程并发的操作共享变量,会带来⼀些问题。
样例代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
int ticket = 100;
void *route(void *arg)
{
char *id = (char *)arg;
while (1)
{
if (ticket > 0)
{
usleep(1000);
printf("%s sells ticket:%d\n", id, ticket);
ticket--;
}
else
{
break;
}
}
}
int main(void)
{
pthread_t t1, t2, t3, t4;
pthread_create(&t1, NULL, route, (void *)"thread 1");
pthread_create(&t2, NULL, route, (void *)"thread 2");
pthread_create(&t3, NULL, route, (void *)"thread 3");
pthread_create(&t4, NULL, route, (void *)"thread 4");
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
pthread_join(t4, NULL);
return 0;
}
互斥量的接⼝
初始化
静态分配
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
动态分配
int pthread_mutex_init(pthread_mutex_t restrict mutex, const pthread_mutexattr_t restrict attr);
参数:
mutex :要初始化的互斥量
attr : NULL
销毁:
int pthread_mutex_destroy(pthread_mutex_t *mutex) ;
1、静态分配的互斥量不需要销毁
2、不要销毁⼀个已经加锁的互斥量
3、已经销毁的互斥量,要确保后⾯不会有线程再尝试加锁
互斥量加锁和解锁
int pthread_mutex_lock(pthread_mutex_t mutex); // 加锁
int pthread_mutex_unlock(pthread_mutex_t mutex); // 解锁
返回值 : 成功返回 0, 失败返回错误号
封装互斥量
Mutex.hpp
#pragma once
#include<iostream>
#include<pthread.h>
class Mutex
{
public:
Mutex()
{
pthread_mutex_init(&_lock , nullptr);
}
void Lock()
{
pthread_mutex_lock(&_lock);
}
void Unlock()
{
pthread_mutex_unlock(&_lock);
}
~Mutex()
{
pthread_mutex_destroy(&_lock);
}
private:
pthread_mutex_t _lock;
};
class LockGuard
{
public:
LockGuard(Mutex &lock):_lockref(lock)
{
_lockref.Lock();
}
~LockGuard()
{
_lockref.Unlock();
}
private:
Mutex &_lockref;
};
Main.cc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
#include "Mutex.hpp"
int ticket = 1000;
Mutex lock;
void *route(void *arg)
{
char *id = (char *)arg;
while (1)
{
{
// 在该作用域中创建lockguard类对象时自动调用构造函数,此时成员Mutex类(_Mutex)会通过构造函数初始化互斥量,并对互斥量上锁
LockGuard lockguard(lock);
if (ticket > 0)
{
usleep(1000);
printf("%s sells ticket:%d\n", id, ticket);
ticket--;
}
else
{
break;
}
// 离开该作用域时lockguard 会自动调用析构函数对互斥量进行解锁操作
}
}
return nullptr;
}
int main(void)
{
pthread_t t1, t2, t3, t4;
pthread_create(&t1, NULL, route, (void *)"thread-1");
pthread_create(&t2, NULL, route, (void *)"thread-2");
pthread_create(&t3, NULL, route, (void *)"thread-3");
pthread_create(&t4, NULL, route, (void *)"thread-4");
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
pthread_join(t4, NULL);
return 0;
}
makefile
thread:Main.cc
g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
rm -f thread
