线程同步
来源:互联网 发布:种子搜索 知乎 编辑:程序博客网 时间:2024/05/21 08:41
当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图。原因在于,当多个线程同时读取和修改变量时,会造成共享变量的不一致,因此需要对线程进行同步,确保他们在访问变量的存储内容时不会访问到无效的值。
互斥量
可以使用pthread的互斥接口来保护数据,确保同一时间只有一个线程访问数据。互斥量(mutex)本质上是一把锁,在访问共享资源前对互斥量进行设置(加锁),在访问结束后释放(解锁)互斥量。对互斥量加锁以后,任何其他试图再次对互斥量加锁的线程都会被堵塞,直到当前线程释放该互斥锁。如果释放互斥量时有一个以上的线程阻塞,那么所有的该锁上的阻塞线程都会变成可运行状态,第一个变为运行的线程可以对互斥量加锁,其他线程就会看到互斥量是锁着的,只能再次阻塞直到互斥量变为可用。这种方式下,每次只有一个线程可以执行。
只有将所有线程都设计成遵守相同数据访问规则的,互斥机制才能正常工作。操作系统并不为我们做数据访问的串行化。如果允许某个线程在没有得到锁的情况下也可以访问共享资源,那么即使其他的线程在使用共享资源前都申请锁,也还是会出现数据不一致的问题。
互斥变量是用pthread_mutex_t数据类型表示。在使用互斥变量以前,必须首先对它进行初始化,可以把它设置为常量PTHREAD_MUTEX_INITIALIZER(只适用于静态分配的互斥量),也可以调用pthread_mutex_init函数进行初始化。如果动态分配互斥量(例如,通过调用malloc函数),在释放内存前需要调用pthread_mutex_destory。
#include <pthread.h>pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_trylock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);int pthread_mutex_destroy(pthread_mutex_t *mutex);-------------------------------------------------pthread_mutex_init always returns 0. The other mutex functions return 0 on success and a non-zero error code on error.
pthread_mutex_trylock尝试对互斥量加锁,成功返回0,否则不能加互斥锁,返回EBUSY。
#include <stdio.h>#include <stdlib.h>#include <pthread.h>typedef struct foo{ int f_count; pthread_mutex_t f_lock; int f_id; /* ... more stuff here ...*/} foo;/* allocate the object */foo*foo_alloc(int id) { foo *fp; if((fp = malloc(sizeof(foo))) != NULL) { fp->f_count = 1; fp->f_id = id; if(pthread_mutex_init(&fp->f_lock, NULL) != 0) { free(fp); return NULL; } } return fp;}/* add a reference to the object */voidfoo_hold(foo *fp){ pthread_mutex_lock(&fp->f_lock); fp->f_count ++; pthread_mutex_unlock(&fp->f_lock);}/* release a reference tp the object */voidfoo_rele(foo *fp){ pthread_mutex_lock(&fp->f_lock); if(--fp->f_count == 0) { pthread_mutex_unlock(&fp->f_lock); pthread_mutex_destroy(&fp->f_lock); } else { pthread_mutex_unlock(&fp->f_lock); }}
避免死锁
- 如果线程尝试对同一个互斥锁加锁两次,那么自身会陷入死锁状态;
- 程序中使用一个以上的互斥量时,如果允许一个线程一直占有第一个互斥量,并且在尝试锁住第二个互斥量时处于阻塞状态,但是拥有第二个互斥量的线程也在试图锁住第一个互斥量,因为两个线程都在相互请求另一个线程拥有的资源,所以这两个线程都无法向前运行,于是就产生死锁;
避免死锁的方法
- 仔细控制互斥量加锁的顺序来避免死锁的发生;
- 使用pthread_mutex_trylock接口避免死锁;
线程退出时并不会释放当前持有且未释放的mutex锁,因此当其他线程在申请此锁时会被阻塞;只有当线程所在的进程退出时,mutex锁才会被操作系统释放。
// Example:zhuqingping@ubuntu:~/Study/C/pthread$ cat thread_exit_without_release_lock.c #include <pthread.h>#include <stdio.h>#include <stdlib.h>pthread_mutex_t fastmutex;void *my_new_thread(void *args){ printf("New Thread Start\n"); pthread_mutex_lock(&fastmutex); printf("New Thread End\n"); return NULL;}int main(){ pthread_t new_thread; pthread_mutex_init(&fastmutex, NULL); if(pthread_create(&new_thread, NULL, my_new_thread, NULL) != 0) { printf("new thread create error\n"); return -1; } sleep(2); pthread_mutex_lock(&fastmutex); printf("Main Thread\n"); pthread_mutex_unlock(&fastmutex); pthread_mutex_destroy(&fastmutex); return 0;}zhuqingping@ubuntu:~/Study/C/pthread$ ./thread_exit_without_release_lock New Thread StartNew Thread End^Czhuqingping@ubuntu:~/Study/C/pthread$
- 线程同步--线程同步--线程同步--线程同步--线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- 线程同步
- Deep Learning论文笔记之(一)K-means特征学习
- SQL性能优化十条经验
- Deep Learning论文笔记之(二)Sparse Filtering稀疏滤波
- Android -- Init进程对属性系统的处理流程分析
- Deep Learning论文笔记之(三)单层非监督学习网络分析
- 线程同步
- Deep Learning论文笔记之(四)CNN卷积神经网络推导和实现
- 2017-2-9自学第一课
- [netty核心类]--ChannelPipeline和ChannelHandler源码分析
- Deep Learning论文笔记之(五)CNN卷积神经网络代码理解
- redis--数据类型
- Deep Learning论文笔记之(六)Multi-Stage多级架构分析
- .Net下的分库分表帮助类——用分库的思想来分表
- Deep Learning论文笔记之(七)深度网络高层特征可视化