Linux中的多任务互斥和同步
互斥和同步概述
在多任务操作系统中,同时运行的多个任务可能
-都需要访问/使用同一种资源
-多个任务之间有依赖关系,某个任务的运行依赖于另一个任务
同步和互斥就是用于解决这两个问题的。
》 互斥:
*进程/线程间排斥使用临界资源。
一个公共资源同一时刻只能被一个进程或线程使用,多个进程或线程不能同时使用公共资源。POSIX标准中进程和线程同步和互斥的方法,主要有信号量和互斥锁两种方式。
》 同步:
*进程依赖其他进程的资源
两个或两个以上的进程或线程在运行过程中协同步调,按预定的先后次序运行。
互斥锁
互斥锁(mutex)
mutex是一种简单的加锁的方法来控制对共享资源的访问,mutex只有两种状态,即上锁(lock)和解锁(unlock)。
》 在访问该资源前,首先应申请mutex,如果mutex处于unlock状态,则会申请到mutex并立即lock;如果mutex处于lock状态,则默认阻塞申请者。
》 unlock操作应该由lock者进行。
》 mutex用pthread_mutex_t数据类型表示,在使用互斥锁前,必须先对它进行初始化。
》 静态分配的互斥锁:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
》 动态分配互斥锁:
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
在所有使用过此互斥锁的线程都不再需要使用时候,应调用pthread_mutex_destroy销毁互斥锁。
#include <pthread.h>
int pthread_mutex_init(
pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
功能:
初始化一个互斥锁。
参数:
mutex:互斥锁地址。
attr:互斥锁的属性,NULL为默认的属性。
返回值:
成功返回0,失败返回非0。
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:
对互斥锁上锁,若已经上锁,则调用者一直阻塞到
互斥锁解锁。
参数:
mutex:互斥锁地址。
返回值:
成功返回0,失败返回非0。
#include <pthread.h>
int pthread_mutex_trylock(pthread_mutex_t *mutex);
功能:
对互斥锁上锁,若已经上锁,则上锁失败,函数立即返回。
参数:
mutex:互斥锁地址。
返回值:
成功返回0,失败返回非0。
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:
对指定的互斥锁解锁。
参数:
mutex:互斥锁地址。
返回值:
成功返回0,失败返回非0。
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:
销毁指定的一个互斥锁。
参数:
mutex:互斥锁地址。
返回值:
成功返回0,失败返回非0。
例:01_pthread_mutex.c

信号量
*死锁
》 一组进程中的每个进程均无限期地等待被该组进程中的另一进程所占有且永远不会释放的资源时(进程竞争),资源出现了循环等待,这种状态称为死锁 。
》 死锁产生的原因:
系统提供的资源有限;进程推进顺序不当。
》 死锁产生的必要条件:
互斥条件、不可剥夺条件、请求和保持条件、循环等待条件。
*线程池
》 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。
》 作用:节约处理器资源,提升响应速度,便于操作系统调度管理;
》 原理:创建有限数量的线程,通过避免线程的大量创建与销毁,重复利用已创建的线程,实现资源的充分利用和时间的节约。
- 信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。
- 编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于0时,则可以访问,否则将阻塞。
- PV原语是对信号量的操作,一次P操作使信号量sem减1,一次V操作使信号量sem加1。
- 信号量主要用于进程或线程间的同步和互斥这两种典型情况。
》若用于互斥,几个进程(或线程)往往只设置一个信号量。
》若用于同步操作,往往会设置多个信号量,并且安排不同的初始值,来实现它们之间的执行顺序。
信号量用于互斥![image]()
信号量用于同步![image]()
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared,unsigned int value);
功能:
创建一个信号量并初始化它的值。
参数:
sem:信号量的地址。
pshared:等于0,信号量在线程间共享;
不等于0,信号量在进程间共享。
value:信号量的初始值。
返回值:
成功返回0,失败返回-1。
#include <semaphore.h>
int sem_wait(sem_t *sem);
功能:
将信号量的值减1,若信号量的值小于0,此函数会引起调用者阻塞。
参数:
sem:信号量地址。
返回值:
成功返回0,失败返回-1。
#include <semaphore.h>
int sem_trywait(sem_t *sem);
功能:
将信号量的值减1,若信号量的值小于0,则对信号量的操作失败,函数立即返回。
参数:
sem:信号量地址。
返回值:
成功返回0,失败返回-1。
#include <semaphore.h>
int sem_post(sem_t *sem);
功能:
将信号量的值加1并发出信号唤醒等待线程。
参数:
sem:信号量地址。
返回值:
成功返回0,失败返回-1。
#include <semaphore.h>
int sem_getvalue(sem_t *sem, int *sval);
功能:
获取sem标识的信号量的值,保存在sval中。
参数:
Ø sem:信号量地址。
Ø sval:保存信号量值的地址。
返回值:
成功返回0,失败返回-1。
#include <semaphore.h>
int sem_destroy(sem_t *sem);
功能:
删除sem标识的信号量。
参数:
sem:信号量地址。
返回值:
成功返回0,失败返回-1。
例:02_semphore_1.c
02_semphore_2.c


有名信号量
其实POSIX的信号量有两种:
1、无名信号量
2、有名信号量
前面我们介绍的就是无名信号量,无名信号量一般用于线程间同步或互斥。而有名信号量一般用于进程间同步或互斥。
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
当信号量存在时使用:
sem_t *sem_open(const char *name, int oflag);
当信号量不存在时使用:
sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);
功能:
创建一个信号量。
参数:
name:信号量文件名。
flags:sem_open函数的行为标志。
mode:文件权限(可读、可写、可执行)的设置。
value :信号量初始值。
返回值:
成功返回信号量的地址,失败返回SEM_FAILED。
#include <semaphore.h>
int sem_close(sem_t *sem);
功能:
关闭有名信号量。
参数:
sem:指向信号量的指针。
返回值:
成功返回0,失败返回-1。
#include <semaphore.h>
int sem_unlink(const char *name);
功能:
删除信号量的文件。
参数:
name:信号量文件名。
返回值:
成功返回0,失败返回-1。
本文来自博客园,作者:早晨9点,转载请注明原文链接:https://www.cnblogs.com/onesun/p/15218443.html



浙公网安备 33010602011771号