2019インディアン8越15木曜日日
。スレッド排他的-ミューテックス。
1.ミューテックスとは何ですか?どのような機能?
ロック状態:mutexがスレッド相互に排他的に対処する方法のために設計されて、それは2つの状態があり/アンロック状態を。
特長:処理状況がロックされている場合、あなたは再ロックするために、リリース日までにロックすることはできません。それがロック解除されている場合は、ロックを解除するには、再度ロックするまでロックを解除することはできません。
2.スレッド相互に排他的にロックAPIの関数インタフェース?
0)が定義ミューテックス変数(pthread_mutex_t->ミューテックスデータ型)
pthread_mutex_tミューテックス;
1)ミューテックスを初期化 > pthread_mutex_initの() - - >男性 3 pthread_mutex_initのを
機能:ミューテックスを初期化-ミューテックスを初期化します>
フォーマットを使用します:
書式#include <pthread.hの>
- >ダイナミック初期化
int型pthread_mutex_initの(pthread_mutex_t *ミューテックス、constのpthread_mutexattr_t * ATTR);
ミューテックス: ミューテックスアドレス
ATTR: 一般的に満たされたmutex属性、NULL
戻り値:
成功:0
失敗しました:エラーコード
- >静的初期化
pthread_mutex_tミューテックス= PTHREAD_MUTEX_INITIALIZER。
2)上锁 - > pthread_mutex_lockの() - >マン3 pthread_mutex_lockの
機能:ミューテックスをロック
フォーマットを使用します:
書式#include <pthread.hの>
int型は、pthread_mutex_lock(pthread_mutex_t *ミューテックス)。
ミューテックス:ミューテックスアドレスを初期化されている必要があります
戻り値:
成功:0
失敗しました:エラーコード
3)解锁 - > pthread_mutex_unlockの() - >男3 pthread_mutex_unlockの
機能:mutexをロック解除
フォーマットを使用します:
書式#include <pthread.hの>
int型pthread_mutex_unlockの(pthread_mutex_t *ミューテックス)。
ミューテックス:ミューテックスアドレスを初期化されている必要があります
戻り値:
成功:0
失敗しました:エラーコード
4)ミューテックス破壊 > pthread_mutex_destroyのを() - - >男性 3 pthread_mutex_destroyの
特徴:
フォーマットを使用します:
書式#include <pthread.hの>
int型pthread_mutex_destroyの(pthread_mutex_t *ミューテックス)。
ミューテックス:ミューテックスアドレスを初期化されている必要があります
戻り値:
成功:0
失敗しました:エラーコード
練習1:仕事完了するために、ミューテックスを使用した2。
#include "head.h"
pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER。
//ジャックの毛
void *型routine1(ボイド*引数)
{
CHAR * P =(CHAR *)引数。
一方、(1)
{
あなたが共有メモリにアクセスする前に//がロックを解除する必要があります
pthread_mutex_lockの(&M)。
関数fgets(P、1024、STDIN); //共有メモリへのアクセス
//共有メモリへのアクセスが終了した後ロックを解除する必要があります
pthread_mutex_unlockの(&M)。
(strncmpは(P、 "終了"、4)== 0)の場合
{
ブレーク;
}
usleep(100000)。
}
pthread_exit(NULL)。
}
//ローズ収入
void *型routine2(ボイド*引数)
{
usleep(100000)。
CHAR * P =(CHAR *)引数。
一方、(1)
{
//共有メモリにアクセスする前にロックする必要がありますロックした後、睡眠のために、
pthread_mutex_lockの(&M)。
printf("from Jack:%s",p);
pthread_mutex_unlock(&m);
if(strncmp(p,"quit",4) == 0)
{
break;
}
usleep(200000);
}
pthread_exit(NULL);
}
int main(int argc,char *argv[])
{
//1. 申请key与ID号
key_t key = ftok(".",10);
int shmid = shmget(key,1024,IPC_CREAT|0666);
//2. 映射内存空间
char *p = shmat(shmid,NULL,0);
//3. 产生Jack线程与Rose线程
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,routine1,(void *)p);
pthread_create(&tid2,NULL,routine2,(void *)p);
//4. 接合线程
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
//5. 撤销映射,删除共享内存ID
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
结论:只要工程涉及到共享资源(共享内存,链表,文件..),就必须在访问前上锁,访问后解锁。
二. 读写锁。
1. 互斥锁有什么缺陷?
互斥锁无论是访问资源,还是修改资源都必须要上锁,而且在上锁期间不能被别的线程再上锁。
访问资源(一起读这本书) -> 同时上读锁 -> 读锁其实是一把共享锁。
修改资源(修改书本的数据) -> 不能同时上写锁 -> 写锁其实是一把互斥锁。
即有读锁,又有写锁,那么我们就称之为读写锁。
2. 关于读写锁的API函数接口?
1)初始化读写锁 -> pthread_rwlock_init() -> man 3 pthread_rwlock_init
功能:initialize a read-write lock object
使用格式:
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *rwlock,const pthread_rwlockattr_t *attr);
rwlock: 读写锁的地址
attr: 属性,一般填NULL
返回值:
成功:0
失败:错误码
2)读锁上锁 -> pthread_rwlock_rdlock() -> man 3 pthread_rwlock_rdlock
功能:lock a read-write lock object for reading
使用格式:
#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
rwlock:读写锁的地址
返回值:
成功:0
失败:错误码
3)写锁上锁 -> pthread_rwlock_wrlock() -> man 3 pthread_rwlock_wrlock
功能:lock a read-write lock object for writing
使用格式:
#include <pthread.h>
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
rwlock:读写锁的地址
返回值:
成功:0
失败:错误码
4)读写锁解锁 -> pthread_rwlock_unlock() -> man 3 pthread_rwlock_unlock
功能:unlock a read-write lock object
使用格式:
#include <pthread.h>
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
rwlock:读写锁的地址
返回值:
成功:0
失败:错误码
5)销毁读写锁 -> pthread_rwlock_destroy() -> man 3 pthread_rwlock_destroy
功能:destroy a read-write lock object
使用格式:
#include <pthread.h>
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
rwlock:读写锁的地址
返回值:
成功:0
失败:错误码
练习2:临界资源"int a",两个线程想打印a的值,两个线程想修改a的值。
验证:
1)读锁可以同时上,但是写锁不可以同时上。
2)读锁写锁能不能同时上? -> 不可以,写锁等到读锁解开之后才能上写锁。
#include "head.h"
int a = 100;//临界资源
pthread_rwlock_t rwlock; //读写锁变量
//线程1任务:打印a的值,花了3秒
void *fun1(void *arg)
{
//访问临界资源前,需要上读锁
pthread_rwlock_rdlock(&rwlock);
printf("fun1 rdlock lock!\n");
printf("fun1 a = %d\n",a);
sleep(3);
//访问完临界资源,需要解锁
pthread_rwlock_unlock(&rwlock);
printf("fun1 rdlock unlock!\n");
pthread_exit(NULL);
}
//线程2任务:打印a的值,花了5秒
void *fun2(void *arg)
{
//访问临界资源前,需要上读锁
pthread_rwlock_rdlock(&rwlock);
printf("fun2 rdlock lock!\n");
printf("fun2 a = %d\n",a);
sleep(5);
//访问完临界资源,需要解锁
pthread_rwlock_unlock(&rwlock);
printf("fun2 rdlock unlock!\n");
pthread_exit(NULL);
}
//线程3任务:修改a的值,花了4S a = 50
void *fun3(void *arg)
{
pthread_rwlock_wrlock(&rwlock);
printf("fun3 wrlock lock!\n");
a = 50;
sleep(4);
pthread_rwlock_unlock(&rwlock);
printf("fun3 wrlock unlock!\n");
pthread_exit(NULL);
}
//线程4任务:修改a的值,花了6S a = 30
void *fun4(void *arg)
{
pthread_rwlock_wrlock(&rwlock);
printf("fun4 wrlock lock!\n");
a = 30;
sleep(6);
pthread_rwlock_unlock(&rwlock);
printf("fun4 wrlock unlock!\n");
pthread_exit(NULL);
}
void *routine(void *arg)
{
int i;
for(i=0;i<1000000;i++)
{
printf("%d\n",i);
sleep(1);
}
}
int main(int argc,char *argv[])
{
//0. 计算时间的流逝
pthread_t tid;
pthread_create(&tid,NULL,routine,NULL);
//1. 初始化读写锁
pthread_rwlock_init(&rwlock,NULL);
//2. 产生子线程
pthread_t tid1,tid2,tid3,tid4;
pthread_create(&tid1,NULL,fun1,NULL);
pthread_create(&tid2,NULL,fun2,NULL);
pthread_create(&tid3,NULL,fun3,NULL);
pthread_create(&tid4,NULL,fun4,NULL);
//3. 接合线程
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
pthread_join(tid4,NULL);
//4. 销毁读写锁
pthread_rwlock_destroy(&rwlock);
return 0;
}
三. 条件变量。
1. 什么是条件变量?特点?
线程因为某个条件不成立/情况不允许情况下,进入一个变量中等待,这个可以存放这些线程的变量就叫做条件变量。
条件变量一定是与互斥锁一起使用。
2. 关于条件变量的函数接口?
0)定义条件变量 (数据类型:pthread_cond_t)
pthread_cond_t v;
1)初始化条件变量? -> pthread_cond_init() -> man 3 pthread_cond_init
功能:initialize condition variables
使用格式:
动态初始化:
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cond,const pthread_condattr_t *attr);
cond: 条件变量的地址
attr: 条件变量的属性,一般填NULL。
返回值:
成功:0
失败:错误码
静态初始化:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
2)如何进入条件变量中等待? -> pthread_cond_wait() -> man 3 pthread_cond_wait
如果满足进入条件变量的条件,则会进去等待,并且会自动解锁。
功能:wait on a condition
使用格式:
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
cond:条件变量的地址
mutex:互斥锁的地址
返回值:
成功:0
失败:错误码
3)如何唤醒条件变量中等待的线程?
广播: 唤醒所有在条件变量中等待的线程。 -> pthread_cond_broadcast() -> man 3 pthread_cond_broadcast
单播: 随机唤醒条件变量中任意一个线程。 -> pthread_cond_signal() -> man 3 pthread_cond_signal
功能:broadcast or signal a condition
使用格式:
#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
cond:条件变量的地址
返回值:
成功:0
失败:错误码
注意: 从条件变量中出来的线程,会自动上锁。
4)销毁条件变量 -> pthread_cond_destroy() -> man 3 pthread_cond_destroy
功能:destroy condition variables
使用格式:
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
cond:条件变量的地址
返回值:
成功:0
失败:错误码
#include "head.h"
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;//初始化互斥锁
pthread_cond_t v = PTHREAD_COND_INITIALIZER;//初始化条件变量
int sum = 400;
//任务: 就是去银行卡扣200块
void *routine(void *arg)
{
//1. 访问临界资源(银行卡)前,都需要上锁
pthread_mutex_lock(&m);
//2. 询问条件是否满足?
while(sum < 200) //当拿不到钱时
{
//就进入条件变量中等待
pthread_cond_wait(&v,&m); //自动解锁。
}
/* 从循环出来,一定是被唤醒并且余额>=200 */
printf("before money:%d\n",sum);
//拿钱
sum -= 200;
printf("after money:%d\n",sum);
//拿到钱后,要主动解锁。
pthread_mutex_unlock(&m);
//走人
pthread_exit(NULL);
}
void *routine1(void *arg)
{
int i;
for(i=0;i<1000000;i++)
{
printf("%d\n",i);
sleep(1);
}
}
int main(int argc,char *argv[])
{
//0. 计算时间的流逝
pthread_t tid_test;
pthread_create(&tid_test,NULL,routine1,NULL);
int i;
pthread_t tid[5];
//1. 产生5个子线程
for(i=0;i<5;i++)
{
pthread_create(&tid[i],NULL,routine,NULL);
}
sleep(5); //2个能拿到钱,3个在条件变量中睡觉。
/* 主线程在访问临界资源前,也必须上锁 */
pthread_mutex_lock(&m);
sum += 400;
printf("main thread + 400!\n");
//拿完钱后,需要解锁
pthread_mutex_unlock(&m);
sleep(2);
//唤醒所有的线程起来拿钱
pthread_cond_broadcast(&v); //2个拿到钱,还有1个因为拿不到钱再回去睡觉。
printf("broarcast!\n");
sleep(3);
pthread_mutex_lock(&m);
sum += 200;
printf("main thread + 200!\n");
//拿完钱后,需要解锁
pthread_mutex_unlock(&m);
pthread_cond_signal(&v);
printf("signal!\n");
for(i=0;i<5;i++)
{
pthread_join(tid[i],NULL);
}
pthread_mutex_destroy(&m);
pthread_cond_destroy(&v);
return 0;
}