#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <pthread.h> typedef struct ct_sum { int sum; pthread_mutex_t lock; } ct_sum; void * add1(void * cnt) { pthread_mutex_lock(&(((ct_sum*) cnt)->lock)); int i; for (i = 0; i < 50; i++) { (*(ct_sum*) cnt).sum += i; } pthread_mutex_unlock(&(((ct_sum*) cnt)->lock)); pthread_exit(NULL); return 0; } void * add2(void *cnt) { int i; cnt = (ct_sum*) cnt; pthread_mutex_lock(&(((ct_sum*) cnt)->lock)); for (i = 50; i < 101; i++) { (*(ct_sum*) cnt).sum += i; } pthread_mutex_unlock(&(((ct_sum*) cnt)->lock)); pthread_exit(NULL); return 0; } int main(void) { int i; pthread_t ptid1, ptid2; int sum = 0; ct_sum cnt; pthread_mutex_init(&(cnt.lock), NULL); cnt.sum = 0; pthread_create(&ptid1, NULL, add1, &cnt); pthread_create(&ptid2, NULL, add2, &cnt); pthread_mutex_lock(&(cnt.lock)); printf("sum %d\n", cnt.sum); pthread_mutex_unlock(&(cnt.lock)); pthread_join(ptid1, NULL); pthread_join(ptid2, NULL); pthread_mutex_destroy(&(cnt.lock)); return 0; }
linux下为了多线程同步,一般用到锁的概念。html
互斥锁是一种经过简单的加锁的方法来控制对共享资源的存取,用于解决线程间资源访问的惟一性问题。互斥锁有上锁和解锁两种状态,在同一时刻只能有一个线程掌握某个互斥的锁,拥有上锁状态的线程能够对共享资源进行操做。若其余线程但愿对一个已经上了锁的互斥锁上锁,则该线程会被挂起,直到上锁的线程释放掉互斥锁为止。linux
posix下抽象了一个锁类型的结构:ptread_mutex_t。经过对该结构的操做,来判断资源是否能够访问。顾名思义,加锁(lock)后,别人就没法打开,只有当锁没有关闭(unlock)的时候才能访问资源。
它主要用以下5个函数进行操做。
1:pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t *attr); 初始化锁变量mutex。attr为锁属性,NULL值为默认属性。
2:pthread_mutex_lock(pthread_mutex_t *mutex);加锁
3:pthread_mutex_tylock(pthread_mutex_t *mutex);加锁,可是与2不同的是当锁已经在使用的时候,返回为EBUSY,而不是挂起等待。
4:pthread_mutex_unlock(pthread_mutex_t *mutex);释放锁安全
5:pthread_mutex_destroy(pthread_mutex_t *mutex);使用完后释放多线程
动态方式是采用pthread_mutex_init()函数来初始化互斥锁,API定义以下: int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr) 其中mutexattr用于指定互斥锁属性(见下),若是为NULL则使用缺省属性。 有两种方法建立互斥锁,静态方式和动态方式。POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,方法以下: pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; 在LinuxThreads实现中,pthread_mutex_t是一个结构,而PTHREAD_MUTEX_INITIALIZER则是一个结构常量。异步
pthread_mutex_destroy ()用于注销一个互斥锁,API定义以下: int pthread_mutex_destroy(pthread_mutex_t *mutex) 销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。因为在Linux中,互斥锁并不占用任何资源,所以LinuxThreads中的 pthread_mutex_destroy()除了检查锁状态之外(锁定状态则返回EBUSY)没有其余动做。函数
* PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁之后,其他请求锁的线程将造成一个等待队列,并在解锁后按优先级得到锁。这种锁策略保证了资源分配的公平性。 互斥锁的属性在建立锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不一样的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不一样。当前(glibc2.2.3,linuxthreads0.9)有四个值可供选择:测试
* PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,容许同一个线程对同一个锁成功得到屡次,并经过屡次unlock解锁。若是是不一样线程请求,则在加锁线程解锁时从新竞争。spa
* PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,若是同一个线程请求同一个锁,则返回EDEADLK,不然与PTHREAD_MUTEX_TIMED_NP类型动做相同。这样就保证当不容许屡次加锁时不会出现最简单状况下的死锁。线程
* PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动做最简单的锁类型,仅等待解锁后从新竞争。nuxt
int pthread_mutex_lock(pthread_mutex_t *mutex) 锁操做主要包括加锁pthread_mutex_lock()、解锁pthread_mutex_unlock()和测试加锁 pthread_mutex_trylock()三个,不论哪一种类型的锁,都不可能被两个不一样的线程同时获得,而必须等待解锁。对于普通锁和适应锁类型,解锁者能够是同进程内任何线程;而检错锁则必须由加锁者解锁才有效,不然返回EPERM;对于嵌套锁,文档和实现要求必须由加锁者解锁,但实验结果代表并无这种限制,这个不一样目前尚未获得解释。在同一进程中的线程,若是加锁后没有解锁,则任何其余线程都没法再得到锁。
int pthread_mutex_unlock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
pthread_mutex_trylock()语义与pthread_mutex_lock()相似,不一样的是在锁已经被占据时返回EBUSY而不是挂起等待。
这个锁机制同时也不是异步信号安全的,也就是说,不该该在信号处理过程当中使用互斥锁,不然容易形成死锁。POSIX 线程锁机制的Linux实现都不是取消点,所以,延迟取消类型的线程不会因收到取消信号而离开加锁等待。值得注意的是,若是线程在加锁后解锁前被取消,锁将永远保持锁定状态,所以若是在关键区段内有取消点存在,或者设置了异步取消类型,则必须在退出回调函数中解锁。
互斥锁属性使用互斥锁(互斥)可使线程按顺序执行。一般,互斥锁经过确保一次只有一个线程执行代码的临界段来同步多个线程。互斥锁还能够保护单线程代码。
互斥锁的一个明显缺点是它只有两种状态:锁定和非锁定。而条件变量经过容许线程阻塞和等待另外一个线程放松信号的方法弥补了互斥锁的不足,它常和互斥锁一块使用。使用时,条件变量被用来阻塞一个线程,当条件不知足时,线程每每解开相应的互斥锁并等待条件发生变化。一旦其余的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正在被此条件阻塞的线程。这些线程将从新锁定互斥锁并从新测试条件是否知足。条件变量上的基本操做有两个。1.触发条件:当条件变为true时;2.等待条件:挂起线程直到其余线程触发条件。条件变量的数据类型是pthreead_cond_t,在使用前也须要初始化。