互斥锁
时间:2021年7月19日14:11:44
pthread_mutex_init函数
SYNOPSIS
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
argument1:互斥锁的ID地址
argument2:指定新建互斥锁的属性,取NULL时,默认属性为快速互斥锁,PTHREAD_PROCESS_PRIVATE 是其缺省值。
互斥锁ID:每一个互斥锁都有一个互斥锁ID。ID类型是pthread_mutex_t
example4s.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
//声明一个锁
pthread_mutex_t lock;
int s;
void *myFunc(void *args)
{
for (int i = 1; i <= 100000; i++)
{
pthread_mutex_lock(&lock); //上锁
s++;
pthread_mutex_unlock(&lock); //解锁
}
return NULL;
}
int main()
{
pthread_t th1;
pthread_t th2;
//对锁进行初始化,即创建一个锁
pthread_mutex_init(&lock, NULL);
pthread_create(&th1, NULL, myFunc, NULL);
pthread_create(&th2, NULL, myFunc, NULL);
//等待线程执行完毕
pthread_join(th1, NULL);
pthread_join(th2, NULL);
printf("s = %d\n", s);
return 0;
}
运行结果:
s = 200000
//声明一个锁
pthread_mutex_t lock;
//对锁进行初始化,即创建一个锁
pthread_mutex_init(&lock,NULL);
pthread_mutex_lock(&lock);//上锁
/*需要上锁的代码*/
pthread_mutex_unlock(&lock);//解锁
当一个以上线程需要用同一部分代码时,为避免资源竞争问题(race condition),将相关代码锁起来;
先到先使用,若线程1先到,使用时先上锁,晚到的线程2等待线程1使用完,打开锁,才能使用(有点像排队上厕所).
多线程效率问题
多核的情况下,会出现假共享(false sharing)
example5.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define MAX_SIZE 50000000
//线程参数结构体
typedef struct
{
int first;
int last;
int result;//存结果
} MY_ARGS;
int *arr;
void *myFunc(void *args)
{
int s = 0;
MY_ARGS *my_args = (MY_ARGS *)args;
int first = my_args->first;
int last = my_args->last;
for (int i = first; i < last; i++)
{
s += arr[i];
}
my_args->result = s;
return NULL;
}
int main()
{
arr = malloc(sizeof(int) * MAX_SIZE);
for (int i = 0; i < MAX_SIZE; i++)
{
arr[i] = rand() % 5; //区间[0, 4],防止结果溢出
}
pthread_t th1;
pthread_t th2;
int mid = MAX_SIZE / 2;
MY_ARGS arg1 = {0, mid, 0};
MY_ARGS arg2 = {mid, MAX_SIZE, 0};
//创建两个线程
pthread_create(&th1, NULL, myFunc, &arg1);
pthread_create(&th2, NULL, myFunc, &arg2);
//等待线程执行完毕
pthread_join(th1, NULL);
pthread_join(th2, NULL);
int s1 = arg1.result;
int s2 = arg2.result;
printf("s1 = %d\n", s1);
printf("s2 = %d\n", s2);
printf("s1 + s2 = %d\n", s1 + s2);
return 0;
}
运行结果:
s1 = 50010613
s2 = 50004629
s1 + s2 = 100015242
real 0m0.480s
user 0m0.462s
sys 0m0.064s
s1 = 50010613
s2 = 50004629
s1 + s2 = 100015242
real 0m0.486s
user 0m0.508s
sys 0m0.024s
example5s.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define MAX_SIZE 50000000
//线程参数结构体
typedef struct
{
int first;
int last;
int id;//线程ID
} MY_ARGS;
int *arr;
int results[2] = {0, 0};//存结果
void *myFunc(void *args)
{
MY_ARGS *my_args = (MY_ARGS *)args;
int first = my_args->first;
int last = my_args->last;
int id = my_args->id;
for (int i = first; i < last; i++)
{
results[id] += arr[i];
}
return NULL;
}
int main()
{
arr = malloc(sizeof(int) * MAX_SIZE);
for (int i = 0; i < MAX_SIZE; i++)
{
arr[i] = rand() % 5; //区间[0, 4],防止结果溢出
}
pthread_t th1;
pthread_t th2;
int mid = MAX_SIZE / 2;
MY_ARGS arg1 = {0, mid, 0};
MY_ARGS arg2 = {mid, MAX_SIZE, 1};
pthread_create(&th1, NULL, myFunc, &arg1);
pthread_create(&th2, NULL, myFunc, &arg2);
pthread_join(th1, NULL);
pthread_join(th2, NULL);
printf("s1 = %d\n", results[0]);
printf("s2 = %d\n", results[1]);
printf("s1 + s2 = %d\n", results[0] + results[1]);
return 0;
}
运行结果:
s1 = 50010613
s2 = 50004629
s1 + s2 = 100015242
real 0m0.774s
user 0m1.038s
sys 0m0.044s
s1 = 50010613
s2 = 50004629
s1 + s2 = 100015242
real 0m0.774s
user 0m1.028s
sys 0m0.068s
程序example5s.c明显比程序example5.c运行速度更慢:
example5s.c程序发生了假共享(false sharing)
多核处理多个线程时,会将数组results的数据分别读入自己的缓存.
-
核1处理线程1,读取数组results,修改results[0]的值 ;
-
同时,核2处理线程2,读取数组results,修改results[1]的值;
-
线程1处理好results[0]写回原数组时,发现核2已经将处理好的results[1]写回去了,线程1中的results[1]和原数组中的不相同,于是将原数组中修改过的results[1]读入核1的results[1]中,再将数组results整个写回原数组.
(也可能是线程1先处理好,线程2遇到false sharing)
example5.c中的s一直都在CPU中,线程交替运行不会重复读写.
而example5s.c的results[0],results[1]都不是CPU中的,线程交替运行时都有读入写入操作.
频繁的读写造成时间的浪费.
多线程到此告一段落.
我感觉下方链接介绍的还可以 – 推荐链接