引入互斥量:
线程间 竞争故障:
实验1:线程间竞争故障,用sleep()放大竞争故障
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#define THRNUM 20
#define FNAME "/home/mhr/Desktop/xitongbiancheng/parallel/thread/posix/out"
#define LINESIZE 1024 //提前写好1
static void *thr_add(void *p)
{
FILE *fp;
char linebuf[LINESIZE];
fp = fopen(FNAME,"r+");
if(fp == NULL)
{
perror("fopen()");
exit(1);
}
fgets(linebuf,LINESIZE,fp);
fseek(fp,0,SEEK_SET);
sleep(1);
fprintf(fp,"%d\n",atoi(linebuf)+1);
fclose(fp);
pthread_exit(NULL);
}
int main()
{
pthread_t tid[THRNUM];
int i,err;
for(i = 0; i < THRNUM; i++)
{
err = pthread_create(tid+i,NULL,thr_add,NULL);
if(err)
{
fprintf(stderr,"pthread_create(): %s\n",strerror(err));
exit(1);
}
}
for(i = 0;i < THRNUM; i++)
{
pthread_join(tid[i],NULL);
}
exit(0);
}
由于是虚拟机 单核,所以模拟不出来多核的效果,故 在thr_add() 中 sleep(1) 一秒,比作调度器调度其他线程,放大各个线程之间的竞争,看结果 发现,创建出来的20个线程,全部都拿到了 FNAME文件,并拿到的值都是1,sleep()后 开始加一写值,导致重复写了20次2值到文件中。
出现这个问题的原因就是 线程之间的竞争导致的。
互斥量:
划红线的这句话太重要了!!! 对互斥量进行加锁以后,任何其他试图再次对互斥量加锁的线程都会被阻塞,直至当前线程释放该互斥锁
就算是自己在没有解锁的情况下,想再次持锁,也会被阻塞!!!
NAME
pthread_mutex_destroy, pthread_mutex_init — destroy and initialize a mutex,初始化和销毁 一个 互斥量
SYNOPSIS
#include <pthread.h>
SYNOPSIS
#include <pthread.h>
//销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//动态初始化
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
//静态初始化方式
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
对互斥量上锁,解锁:
NAME
pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock — lock and unlock a mutex
扫描二维码关注公众号,回复:
12940100 查看本文章
SYNOPSIS
#include <pthread.h>
//以阻塞的方式 限制住某段代码的执行
int pthread_mutex_lock(pthread_mutex_t *mutex);
//以非阻塞的方式 限制住某段代码的执行
int pthread_mutex_trylock(pthread_mutex_t *mutex);
//解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
误区:
不要直接理解为 只要有 pthread_mutex_lock()语句,后面的代码都是临界区,这样容易犯懵。而是要理解为:只我要拿到了锁,那么当其他线程要这个锁的时候,就拿不到锁,就会阻塞。利用这个规则,制造我们需要的临界区。
实验2:修改 上面实验,保证 同一个时间,只能一个人做的代码 为临界区。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#define THRNUM 20
#define FNAME "/home/mhr/Desktop/xitongbiancheng/parallel/thread/posix/out"
#define LINESIZE 1024
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static void *thr_add(void *p)
{
FILE *fp;
char linebuf[LINESIZE];
fp = fopen(FNAME,"r+");
if(fp == NULL)
{
perror("fopen()");
exit(1);
}
pthread_mutex_lock(&mut); //上锁
fgets(linebuf,LINESIZE,fp);
fseek(fp,0,SEEK_SET);
//sleep(1);
fprintf(fp,"%d\n",atoi(linebuf)+1); // 全缓冲,需要fflush 或者 fclose 刷新 才能写到目标文件
fclose(fp);// fprintf(fp 全缓冲,需要fflush 或者 fclose 刷新 才能写到目标文件,所以也在临界区
pthread_mutex_unlock(&mut); //解锁
pthread_exit(NULL);
}
int main()
{
pthread_t tid[THRNUM];
int i,err;
for(i = 0; i < THRNUM; i++)
{
err = pthread_create(tid+i,NULL,thr_add,NULL);
if(err)
{
fprintf(stderr,"pthread_create(): %s\n",strerror(err));
exit(1);
}
}
for(i = 0;i < THRNUM; i++)
{
pthread_join(tid[i],NULL);
}
pthread_mutex_destroy(&mut);
exit(0);
}
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ gcc add.c -lpthread
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ cat out
1
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ ./a.out
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ cat out
21
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ ./a.out
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ cat out
41
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ ./a.out
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ cat out
61
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$
实验 3 ,互斥量,加深理解:规定时间内 四个线程 按顺序 分别不停的向终端 输出 a,b,c,d 每个线程输出一个字母
创建四个互斥锁,四个线程,临界区代码中,每个线程负责持锁,输出,并释放下一个线程的锁。这样 每个线程就可以轮询持锁输出。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#define THRNUM 4
static pthread_mutex_t mut[THRNUM];
static int next(int n)
{
if(n+1 == THRNUM)
return 0;
return n+1;
}
static void *thr_add(void *p)
{
int n = (int)p;
int c = 'a' + (int)p;
while(1)
{
pthread_mutex_lock(mut+n);
write(1,&c,1);
pthread_mutex_unlock(mut+next(n));//这里会执行 被阻塞的目标线程,当前线程由于没有释放自己持有的锁,会被再次阻塞。
}
pthread_exit(NULL);
}
int main()
{
pthread_t tid[THRNUM];
int i,err;
for(i = 0; i < THRNUM; i++)
{
pthread_mutex_init(mut+i,NULL);
pthread_mutex_lock(mut+i);
err = pthread_create(tid+i,NULL,thr_add,(void *)i);
if(err)
{
fprintf(stderr,"pthread_create(): %s\n",strerror(err));
exit(1);
}
}
pthread_mutex_unlock(mut+0);//释放线程1的锁
alarm(5);
for(i = 0;i < THRNUM; i++)
{
pthread_join(tid[i],NULL);
}
exit(0);
}