首页 > 学院 > 开发设计 > 正文

线程同步

2019-11-08 02:12:07
字体:
来源:转载
供稿:网友

当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图。原因在于,当多个线程同时读取和修改变量时,会造成共享变量的不一致,因此需要对线程进行同步,确保他们在访问变量的存储内容时不会访问到无效的值。

互斥量

可以使用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$
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表