20201317-Linux-Thread 互斥测试
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> //linux 线程库
#include <ctype.h> //测试和映射字符的库
struct arg_set {
char *fname;
int count;
};//定义结构体
struct arg_set *mailbox = NULL;//定义结构体指针;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//linux线程创建锁,初始化锁
pthread_cond_t flag = PTHREAD_COND_INITIALIZER; //初始化条件变量,进行静态初始化
void *count_words(void *);//定义函数指针
int main(int argc, char *argv[])
{
pthread_t t1, t2; //进行多线程管理
struct arg_set args1, args2;//初始化两个结构体
int reports_in = 0;
int total_words = 0;
if ( argc != 3 ){
printf("usage: %s file1 file2\n", argv[0]);
exit(1);
}//判断传入参量,参量的数量决定输出用法
args1.fname = argv[1];//args1结构体指向第二个变量
args1.count = 0;//args1结构体初始化count
pthread_create(&t1, NULL, count_words, (void *) &args1);//在执行中创建一个线程, 为该线程分配它需要做的工作(线程执行函数), 该线程共享进程的资源
args2.fname = argv[2];//args2结构体指向第三个变量
args2.count = 0;//args2结构体count初始化
pthread_create(&t2, NULL, count_words, (void *) &args2);//创建线程,并分配需要做的工作和资源,分配共享进程的资源
pthread_mutex_lock(&lock);//加锁
while( reports_in < 2 ){
printf("MAIN: waiting for flag to go up\n");
pthread_cond_wait(&flag, &lock);//阻塞当前线程,等待别的线程使用
printf("MAIN: Wow! flag was raised, I have the lock\n");
printf("%7d: %s\n", mailbox->count, mailbox->fname);
total_words += mailbox->count;//加mailbox的count值
if ( mailbox == &args1)
pthread_join(t1,NULL);
//阻塞调用它的线程,直至目标线程执行结束
if ( mailbox == &args2)
pthread_join(t2,NULL);
mailbox = NULL;
pthread_cond_signal(&flag);
//发送一个信号,给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态
reports_in++;
}
pthread_mutex_unlock(&lock);
//解除锁定mutex所指向的互斥锁的函数
printf("%7d: total words\n", total_words);
}
void *count_words(void *a)
{
struct arg_set *args = a;
//初始化结构体,指向传参a;
FILE *fp;
int c, prevc = '\0';
if ( (fp = fopen(args->fname, "r")) != NULL ){
//成功打开文件
while( ( c = getc(fp)) != EOF ){
if ( !isalnum(c) && isalnum(prevc) )
//isalnum检测字符串是否由字母和数字组成。
args->count++;
//指向的数值count增加1
prevc = c;
}
fclose(fp);
} else
perror(args->fname);
printf("COUNT: waiting to get lock\n");
pthread_mutex_lock(&lock);//上锁
printf("COUNT: have lock, storing data\n");
if ( mailbox != NULL ){
printf("COUNT: oops..mailbox not empty. wait for signal\n");
pthread_cond_wait(&flag,&lock);
}
mailbox = args;
printf("COUNT: raising flag\n");
pthread_cond_signal(&flag);
printf("COUNT: unlocking box\n");
pthread_mutex_unlock(&lock);
return NULL;
}
在线程实际运行过程中,我们经常需要多个线程保持同步。这时可以用互斥锁来完成任务;互斥锁的使用过程中,主要有pthread_mutex_init,pthread_mutex_destory,pthread_mutex_lock,pthread_mutex_unlock这几个函数以完成锁的初始化,锁的销毁,上锁和释放锁操作。
一,锁的创建
锁可以被动态或静态创建,可以用宏PTHREAD_MUTEX_INITIALIZER来静态的初始化锁,采用这种方式比较容易理解,互斥锁是pthread_mutex_t的结构体,而这个宏是一个结构常量,如下可以完成静态的初始化锁:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
另外锁可以用pthread_mutex_init函数动态的创建,函数原型如下:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t * attr)
二,锁的属性
互斥锁属性可以由pthread_mutexattr_init(pthread_mutexattr_t *mattr);来初始化,然后可以调用其他的属性设置方法来设置其属性;
互斥锁的范围:可以指定是该进程与其他进程的同步还是同一进程内不同的线程之间的同步。可以设置为PTHREAD_PROCESS_SHARE和PTHREAD_PROCESS_PRIVATE。默认是后者,表示进程内使用锁。可以使用int pthread_mutexattr_setpshared(pthread_mutexattr_t *mattr, int pshared)
pthread_mutexattr_getshared(pthread_mutexattr_t *mattr,int *pshared)
用来设置与获取锁的范围;
互斥锁的类型:有以下几个取值空间:
PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。
PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。
可以用
pthread_mutexattr_settype(pthread_mutexattr_t *attr , int type)
pthread_mutexattr_gettype(pthread_mutexattr_t *attr , int *type)
获取或设置锁的类型。
三,锁的释放
调用pthread_mutex_destory之后,可以释放锁占用的资源,但这有一个前提上锁当前是没有被锁的状态。
四,锁操作
对锁的操作主要包括加锁 pthread_mutex_lock()、解锁pthread_mutex_unlock()和测试加锁 pthread_mutex_trylock()三个。
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待