linux线程3-互斥与同步
2017-05-30 02:45
676 查看
简介
多线程共享一个进程的地址空间,多线程间通信容易进行,但是多线程同时访问共享对象时需要引入同步和互斥机制.同一个进程的线程共享进程内的绝大部分资源,当一段访问这些共享资源的代码块,有可能被多个线程执行,那么这块代码就被叫做临界区.
当有多个线程并发的在临界区执行时,程序的执行结果会出现不确定性,这种情况被叫做静态条件.
一个demo代码
// // Created by wuxiao on 17-5-29. // #include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <errno.h> #ifndef handle_error_en #define handle_error_en(en,msg)\ errno = en;perror(msg);exit(EXIT_FAILURE); #endif //变量名等规则这里先不考虑 //多线程共享资源 static int global = 0; static void *thread_routine(void *arg) { int loc,j; for(j = 0; j < 10000000;j++) { loc = global; loc++; global = loc; } return nullptr; } int main(int argc,char* argv[]) { pthread_t t1,t2; int result; //创建两个线程,并修改共享资源global result = pthread_create(&t1,NULL,thread_routine,NULL); result += pthread_create(&t2,NULL,thread_routine,NULL); if(result != 0) { handle_error_en(result,"pthread_create"); } //等待子线程退出 result = pthread_join(t1, nullptr); result += pthread_join(t2, nullptr); if(result != 0) { handle_error_en(result,"pthread_join"); } printf("global = %d\n",global); exit(EXIT_SUCCESS); }
- 发现共享变量不是预期值,原因就是进入了静态条件,需要保证多个线程在临界区时互斥的,常用方法是加互斥锁
- 锁分静态和动态:
/ 静态初始化一个全局的互斥锁 pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
#include <pthread.h> // 动态分配一个互斥锁 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); // 释放动态分配的互斥锁 int pthread_mutex_destroy(pthread_mutex_t *mutex);
加锁和解锁:
#include <pthread.h> // 持有互斥锁 int pthread_mutex_lock(pthread_mutex_t *mutex); // 释放互斥锁 int pthread_mutex_unlock(pthread_mutex_t *mutex);
加锁后的demo代码
// // Created by wuxiao on 17-5-29. // #include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <errno.h> #ifndef handle_error_en #define handle_error_en(en,msg)\ errno = en;perror(msg);exit(EXIT_FAILURE); #endif //变量名等规则这里先不考虑 //多线程共享资源 static int global = 0; //静态锁 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; static void *thread_routine(void *arg) { int loc,j; for(j = 0; j < 10000000;j++) { //加锁 pthread_mutex_lock(&mtx); loc = global; loc++; global = loc; //解锁 pthread_mutex_unlock(&mtx); } return nullptr; } int main(int argc,char* argv[]) { pthread_t t1,t2; int result; //创建两个线程,并修改共享资源global result = pthread_create(&t1,NULL,thread_routine,NULL); result += pthread_create(&t2,NULL,thread_routine,NULL); if(result != 0) { handle_error_en(result,"pthread_create"); } //等待子线程退出 result = pthread_join(t1, nullptr); result += pthread_join(t2, nullptr); if(result != 0) { handle_error_en(result,"pthread_join"); } printf("global = %d\n",global); exit(EXIT_SUCCESS); }
线程同步
加解锁一般是为了解决竞态条件的问题,但是有时候我们需要让线程按序执行,4000
这种确保多线程间按照先后顺序执行的技术,就叫做线程同步.
条件变量是线程同步的主要手段,例如线程B调用条件变量让接口阻塞,线程A在处理完资源后,通过条件变量接口来环境等待资源的线程B(有点像中断的感觉..)
条件变量初始化分静态和动态
// 与互斥锁类似静态初始化一个全局的条件变量 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//动态 #include <pthread.h> int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
通知和等待条件变量
include <pthread.h> // 等待一个指定的条件变量 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); // 唤醒一个等待该条件变量的线程 int pthread_cond_signal(pthread_cond_t *cond); // 唤醒所有等待该条件变量的线程 int pthread_cond_broadcast(pthread_cond_t *cond);
demo代码:
// // Created by wuxiao on 17-5-29. // #include <stdio.h> #include <pthread.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <stdint.h> //硬编码,命名等问题先不管 pthread_t threads[2]; char writer_char[2] = {'A','B'}; //锁和条件变量 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //全局写入次数变量 #define MAX_WRITE_TIMES 10 int write_times = 0; struct file_res { //当前文件写入的线程 pthread_t *writer; //文件描述符 int fd; }file_res = { .writer = &threads[0], }; //两个线程的入口函数 void* writer_routine(void *arg) { int index = (intptr_t)arg; size_t i = 0; int next_index = 0; printf("thread %d is running,will write %c\n",index,writer_char[index]); while(1) { //如果已经到达最大写入次数 if(write_times >= MAX_WRITE_TIMES) { //结束当前线程 pthread_exit(NULL); } if(pthread_mutex_lock(&mutex) != 0) { exit(EXIT_FAILURE); } for(;;) { //如果当前线程可写入文件,写文件 if(&threads[index] == file_res.writer) { write(file_res.fd,&writer_char[index],sizeof(writer_char[index])); //更新文件的写入线程 next_index = (index + 1)%2; file_res.writer = &threads[next_index]; write_times++; //跳出死循环,通知下一个线程进场 break; } //当前线程不可写,等待下一个线程唤醒 pthread_cond_wait(&cond,&mutex); } //解锁并唤醒下一个线程 if(pthread_mutex_unlock(&mutex) != 0) { exit(EXIT_FAILURE); } pthread_cond_signal(&cond); } } int main(int argc,char* argv[]) { //创建文件 char file_name[] = "file"; if(file_res.fd = open(file_name,O_RDWR|O_CREAT|O_TRUNC,0666) < 0) { printf("open %s fail\n",file_name); exit(EXIT_FAILURE); } //创建线程1和2 size_t i; for(i = 0;i < sizeof(threads)/sizeof(pthread_t);i++) { if(pthread_create(&threads[i],NULL,writer_routine,(void*)(intptr_t)i) != 0) { printf("create thread %zu fail\n", i); exit(EXIT_FAILURE); } } pthread_exit(NULL); }
相关文章推荐
- 介绍Linux下面线程的操作、多线程的同步和互斥
- Linux多线程编程(二)---线程之间的同步与互斥
- <linux线程>同步互斥机制之【互斥锁】
- Linux多线程编程(不限Linux)——本文一个例子展开,介绍Linux下面线程的操作、多线程的同步和互斥。
- linux 线程创建 同步与互斥
- Linux线程浅析[线程的同步和互斥之线程互斥锁]
- Linux 进程与线程的同步与互斥
- linux内核中多进程(线程)间同步和互斥
- 关于linux中多进程(线程)同步和互斥
- linux中线程的同步和互斥
- Linux环境下线程的同步与互斥以及死锁问题
- linux 系统编程-学习笔记9--线程的同步互斥锁、读写锁/select/poll
- Linux下线程的同步与互斥
- 讲Linux下面线程的操作、多线程的同步和互斥相关函数及操作的文章链接
- 同步事件,信号量,互斥,临界区,线程,线程池C++实现(win32,linux)
- 介绍Linux下面线程的操作、多线程的同步和互斥
- <linux线程>同步互斥机制之【条件变量】
- 本文一个例子展开,介绍Linux下面线程的操作、多线程的同步和互斥
- Linux之线程:同步与互斥
- Linux利用信号量实现线程的同步与互斥