2013-09-16
--luoqindong
线程同步:
<1> 互斥量Mutex
<2> 信号量semaphore
<3> 条件变量conditions
由于线程是共享进程的地址空间,每个线程都可以访问同一个全局变量,所以线程不像进程一样,需要通
信机制去交换数据(线程不像进程存在pipe,消息队列等通信机制,这些通信机制是用来交换数据),线程之间只
需要机制(线程同步)去保证线程A在访问某个全局变量时,线程B不能同时访问,等到线程A访问完之后,线程B才
能访问(保护临界资源).
进程通信:
<1> 管道(pipe)和有名管道(FIFO)
<2> 信号(signal)
<3> 消息队列
<4> 共享内存
<5> 信号量semaphore
<6> 套接字(socket)
驱动并发控制:
<1> 信号量semaphore
<2> 自旋锁spin_lock
<3> completions
线程,进程,驱动的信号量
<1> 线程信号量
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
初始化一个信号量,
sem : 信号量指针,
pshared: 非0时,该信号量可以被其他进程使用(linux太早的版本有可能不支持)
value : 信号量值
int sem_post(sem_t * sem);
信号量值加1
int sem_wait(sem_t * sem);
信号量值减1
int sem_destroy(sem_t * sem);
<2> 进程信号量
#include <sys/sem.h>
int semget(key_t key, int num_sems, int sem_flags);
通过该函数,可以获得一个已经存在的信号量或创建一个新的信号量,该函数返回一个信号量的ID,
其他操作信号量的函数都使用该ID.
key : 不同进程通过该key访问同一个信号量.
num_sems : 创建多少个信号量,通常为1
sem_flags: 如果置成IPC_CREATE, 且key对应的信号量已经存在,semget就返回该信号量,如果想创建一个新的信号号,
使用IPC_CREAT | IPC_EXCL,如果key对应的信号量已经存在,semget返回-1.
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
该函数用来改变信号量的值,相当于线程的sem_post和sem_wait的结合.
sem_id : semget返回的信号量ID
sem_ops: 该结构最少要有以下3个成员
struct sembuf {
short sem_num;
short sem_op;
short sem_flg;
}
sem_num : 当使用多个信号量时(semget函数中的num_sems参数>1),sem_num区别不同的信号量,如果只创建一个信号量,
该值为0.
sem_op : 信号量的值根据该变量值来修改,当为-1时,表示信号量值将减1,相当于sem_wait操作,当为1时,表示信号量
值要加,相当于sem_post操作.
sem_flag: 信号操作标志,可能的选择有两种
IPC_NOWAIT: 对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。
IPC_UNDO : 程序结束时(不论正常或不正常)释放信量,这样做的目的在于避免程序在异常情况下结束时未将锁
定的资源解锁,造成该资源永远锁定.
num_sem_ops:
int semctl(int sem_id, int sem_num, int command, ...);
该函数用来初始化或删除一个信号量.
sem_id : semget返回的信号ID.
sem_num: 当创建多个信号量时,用来区别信号量,相当于数组下标,只有一个信号量时,为0.
command:
SETVAL : 设置信号量的值,当command为该值时,需要第4个参数:
union semun {
int val; // 设置的信号量值
struct semid_ds *buf; //
unsigned short *array; //
}
IPC_RMID : Used for deleting a semaphore identifier when it’s no longer required.
The semctlfunction returns different values depending on the commandparameter. For SETVALand
IPC_RMIDit returns 0 for success and –1 on error.
<3> 驱动信号量
Linux内核的信号量在概念和原理上与用户态的信号量是一样的,但是它不能在内核之外使用,它是一种睡眠锁.
信号量的实现也是与体系结构相关的,定义在<asm/semaphore.h>中,struct semaphore类型用来表示信号量。一般
情况下,信号量保护的临界资源都是可以访问的,因为两个进程同时访问临界资源的情况出现很少,所以信号量的代码针
对一般可访问的这种情况做了优化的.所以要保护的资源在一般情况下不可访问,使用信号量不是最好的方法,可以使用
completions.
初始化信号量
void sema_init (struct semaphore *sem,int val)
该函用于数初始化设置信号量的初值,它设置信号量sem的值为val。
void init_MUTEX (struct semaphore *sem)
该函数用于初始化一个互斥锁,即它把信号量sem的值设置为1。
void init_MUTEX_LOCKED (struct semaphore *sem)
该函数也用于初始化一个互斥锁,但它把信号量sem的值设置为0,即一开始就处在已锁状态。
定义与初始化的工作可由如下宏一步完成:
DECLARE_MUTEX(name)
定义一个信号量name,并初始化它的值为1。
DECLARE_MUTEX_LOCKED(name)
定义一个信号量name,但把它的初始值设置为0,即锁在创建时就处在已锁状态。
获取信号量
void down(struct semaphore * sem)获取信号量sem,可能会致进程睡眠,因此不能在中断上下文使用该函数。该函数
将把sem的值减1,如果信号量sem的值非负,就直接返回,否则调用者将被挂起,直到别的任务释放该信号量才能继续运行。
int down_interruptible(struct semaphore * sem)获取信号量sem。如果信号量不可用,进程将被置为TASK_INTERRUPTIBLE
类型的睡眠状态。该函数由返回值来区分是正常返回还是被信号中断返回,如果返回0,表示获得信号量正常返回,如果被
信号打断,返回-EINTR。
int down_killable(struct semaphore *sem)获取信号量sem。如果信号量不可用,进程将被置为TASK_KILLABLE类型的
睡眠状态。
int down_trylock(struct semaphore *sem);
down_trylock never sleeps; if the semaphore is not available at thetime of the call,down_trylockreturns
immediately with a nonzero return value.
注: down()函数现已不建议继续使用。建议使用down_killable() 或 down_interruptible() 函数。
释放信号量
void up(struct semaphore * sem)该函数释放信号量sem,即把sem的值加1,如果sem的值为非正数,表明有任务等待该
信号量,因此唤醒这些等待者。
线程互斥量
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
int pthread_mutex_lock(pthread_mutex_t *mutex));
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
创建与销毁
在Linux中, 互斥量使用类型pthread_mutex_t表示。在使用前, 要对它进行初始化,对于静态分配的互斥量, 调用宏
PTHREAD_MUTEX_INITIALIZER初始化,对于动态分配的互斥量, 在申请内存(malloc)之后, 通过pthread_mutex_init
进行初始化, 并且在释放内存(free)前需要调用pthread_mutex_destroy。
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
int pthread_mutex_destroy(pthread_mutex_t *mutex)
加锁
对共享资源的访问, 要使用互斥量进行加锁, 如果互斥量已经上了锁, 调用线程会阻塞, 直到互斥量被解锁。
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
返回值: 成功则返回0, 出错则返回错误编号。
trylock是非阻塞调用模式, 如果互斥量没被锁住, trylock函数将对互斥量加锁, 并获得对共享资源的访问权限;
如果互斥量被锁住了, trylock函数将不会阻塞等待而直接返回EBUSY, 表示共享资源处于忙状态。
解锁
在操作完成后,必须给互斥量解锁,也就是前面所说的释放。这样其他等待该锁的线程才有机会获得该锁,否则其他线程将会永远阻塞。
int pthread_mutex_unlock(pthread_mutex_t *mutex)
--luoqindong
线程同步:
<1> 互斥量Mutex
<2> 信号量semaphore
<3> 条件变量conditions
由于线程是共享进程的地址空间,每个线程都可以访问同一个全局变量,所以线程不像进程一样,需要通
信机制去交换数据(线程不像进程存在pipe,消息队列等通信机制,这些通信机制是用来交换数据),线程之间只
需要机制(线程同步)去保证线程A在访问某个全局变量时,线程B不能同时访问,等到线程A访问完之后,线程B才
能访问(保护临界资源).
进程通信:
<1> 管道(pipe)和有名管道(FIFO)
<2> 信号(signal)
<3> 消息队列
<4> 共享内存
<5> 信号量semaphore
<6> 套接字(socket)
驱动并发控制:
<1> 信号量semaphore
<2> 自旋锁spin_lock
<3> completions
线程,进程,驱动的信号量
<1> 线程信号量
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
初始化一个信号量,
sem : 信号量指针,
pshared: 非0时,该信号量可以被其他进程使用(linux太早的版本有可能不支持)
value : 信号量值
int sem_post(sem_t * sem);
信号量值加1
int sem_wait(sem_t * sem);
信号量值减1
int sem_destroy(sem_t * sem);
<2> 进程信号量
#include <sys/sem.h>
int semget(key_t key, int num_sems, int sem_flags);
通过该函数,可以获得一个已经存在的信号量或创建一个新的信号量,该函数返回一个信号量的ID,
其他操作信号量的函数都使用该ID.
key : 不同进程通过该key访问同一个信号量.
num_sems : 创建多少个信号量,通常为1
sem_flags: 如果置成IPC_CREATE, 且key对应的信号量已经存在,semget就返回该信号量,如果想创建一个新的信号号,
使用IPC_CREAT | IPC_EXCL,如果key对应的信号量已经存在,semget返回-1.
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
该函数用来改变信号量的值,相当于线程的sem_post和sem_wait的结合.
sem_id : semget返回的信号量ID
sem_ops: 该结构最少要有以下3个成员
struct sembuf {
short sem_num;
short sem_op;
short sem_flg;
}
sem_num : 当使用多个信号量时(semget函数中的num_sems参数>1),sem_num区别不同的信号量,如果只创建一个信号量,
该值为0.
sem_op : 信号量的值根据该变量值来修改,当为-1时,表示信号量值将减1,相当于sem_wait操作,当为1时,表示信号量
值要加,相当于sem_post操作.
sem_flag: 信号操作标志,可能的选择有两种
IPC_NOWAIT: 对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。
IPC_UNDO : 程序结束时(不论正常或不正常)释放信量,这样做的目的在于避免程序在异常情况下结束时未将锁
定的资源解锁,造成该资源永远锁定.
num_sem_ops:
int semctl(int sem_id, int sem_num, int command, ...);
该函数用来初始化或删除一个信号量.
sem_id : semget返回的信号ID.
sem_num: 当创建多个信号量时,用来区别信号量,相当于数组下标,只有一个信号量时,为0.
command:
SETVAL : 设置信号量的值,当command为该值时,需要第4个参数:
union semun {
int val; // 设置的信号量值
struct semid_ds *buf; //
unsigned short *array; //
}
IPC_RMID : Used for deleting a semaphore identifier when it’s no longer required.
The semctlfunction returns different values depending on the commandparameter. For SETVALand
IPC_RMIDit returns 0 for success and –1 on error.
<3> 驱动信号量
Linux内核的信号量在概念和原理上与用户态的信号量是一样的,但是它不能在内核之外使用,它是一种睡眠锁.
信号量的实现也是与体系结构相关的,定义在<asm/semaphore.h>中,struct semaphore类型用来表示信号量。一般
情况下,信号量保护的临界资源都是可以访问的,因为两个进程同时访问临界资源的情况出现很少,所以信号量的代码针
对一般可访问的这种情况做了优化的.所以要保护的资源在一般情况下不可访问,使用信号量不是最好的方法,可以使用
completions.
初始化信号量
void sema_init (struct semaphore *sem,int val)
该函用于数初始化设置信号量的初值,它设置信号量sem的值为val。
void init_MUTEX (struct semaphore *sem)
该函数用于初始化一个互斥锁,即它把信号量sem的值设置为1。
void init_MUTEX_LOCKED (struct semaphore *sem)
该函数也用于初始化一个互斥锁,但它把信号量sem的值设置为0,即一开始就处在已锁状态。
定义与初始化的工作可由如下宏一步完成:
DECLARE_MUTEX(name)
定义一个信号量name,并初始化它的值为1。
DECLARE_MUTEX_LOCKED(name)
定义一个信号量name,但把它的初始值设置为0,即锁在创建时就处在已锁状态。
获取信号量
void down(struct semaphore * sem)获取信号量sem,可能会致进程睡眠,因此不能在中断上下文使用该函数。该函数
将把sem的值减1,如果信号量sem的值非负,就直接返回,否则调用者将被挂起,直到别的任务释放该信号量才能继续运行。
int down_interruptible(struct semaphore * sem)获取信号量sem。如果信号量不可用,进程将被置为TASK_INTERRUPTIBLE
类型的睡眠状态。该函数由返回值来区分是正常返回还是被信号中断返回,如果返回0,表示获得信号量正常返回,如果被
信号打断,返回-EINTR。
int down_killable(struct semaphore *sem)获取信号量sem。如果信号量不可用,进程将被置为TASK_KILLABLE类型的
睡眠状态。
int down_trylock(struct semaphore *sem);
down_trylock never sleeps; if the semaphore is not available at thetime of the call,down_trylockreturns
immediately with a nonzero return value.
注: down()函数现已不建议继续使用。建议使用down_killable() 或 down_interruptible() 函数。
释放信号量
void up(struct semaphore * sem)该函数释放信号量sem,即把sem的值加1,如果sem的值为非正数,表明有任务等待该
信号量,因此唤醒这些等待者。
线程互斥量
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
int pthread_mutex_lock(pthread_mutex_t *mutex));
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
创建与销毁
在Linux中, 互斥量使用类型pthread_mutex_t表示。在使用前, 要对它进行初始化,对于静态分配的互斥量, 调用宏
PTHREAD_MUTEX_INITIALIZER初始化,对于动态分配的互斥量, 在申请内存(malloc)之后, 通过pthread_mutex_init
进行初始化, 并且在释放内存(free)前需要调用pthread_mutex_destroy。
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
int pthread_mutex_destroy(pthread_mutex_t *mutex)
加锁
对共享资源的访问, 要使用互斥量进行加锁, 如果互斥量已经上了锁, 调用线程会阻塞, 直到互斥量被解锁。
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
返回值: 成功则返回0, 出错则返回错误编号。
trylock是非阻塞调用模式, 如果互斥量没被锁住, trylock函数将对互斥量加锁, 并获得对共享资源的访问权限;
如果互斥量被锁住了, trylock函数将不会阻塞等待而直接返回EBUSY, 表示共享资源处于忙状态。
解锁
在操作完成后,必须给互斥量解锁,也就是前面所说的释放。这样其他等待该锁的线程才有机会获得该锁,否则其他线程将会永远阻塞。
int pthread_mutex_unlock(pthread_mutex_t *mutex)