- 浏览: 517436 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
lin_kk:
最近正在学,请问LZ有源码事例吗,如果有能发一下我邮箱吗,万分 ...
使用libgdx及其中的box2d 2.1的注意事项 -
ahong520:
编译都通不过
ffmpeg对音频解码的一般步骤 -
辽东小小:
yajun_soft 写道XXX@XXX:~$ adb she ...
adb push的Permission denied -
cdtdx:
好文, 相当不错啊. 收了.
什么是app2sd,app2ext,data2ext?app移动到SD卡哪里去了? /mnt/asec /mnt/secure -
dickycat:
学习了,最近正在学这一块,年纪大了,学起来有点吃亏!
使用libgdx及其中的box2d 2.1的注意事项
sem_init:初始化信号量sem_t,初始化的时候可以指定信号量的初始值,以及是否可以在多进程间共享。
sem_wait:一直阻塞等待直到信号量>0。
sem_timedwait:阻塞等待若干时间直到信号量>0。
sem_post:使信号量加1。
sem_destroy:释放信号量。和sem_init对应。
进行多线程编程,最应该注意的就是那些共享的数据,因为无法知道哪个线程会在哪个时候对它进行操作,也无法得知哪个线程会先运行,哪个线程会后运行。所以,要对这些资源进行合理的分配和正确的使用。在Linux下,提供了互斥锁、条件变量和信号量来对共享资源进行保护。
一、互斥锁
互斥锁,是一种信号量,常用来防止两个进程或线程在同一时刻访问相同的共享资源。
需要的头文件:pthread.h
互斥锁标识符:pthread_mutex_t
(1)互斥锁初始化:
函数原型: int pthread_mutex_init (pthread_mutex_t* mutex,const pthread_mutexattr_t* mutexattr);
函数传入值: mutex:互斥锁。
mutexattr:PTHREAD_MUTEX_INITIALIZER 创建快速互斥锁。
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 创建递归互斥锁。
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP 创建检错互斥锁。
函数返回值:成功:0;出错:-1
(2)互斥操作函数
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); //清除互斥锁
函数传入值:mutex:互斥锁。
函数返回值:成功:0;出错:-1
使用形式:
pthread_mutex_t mutex;
pthread_mutex_init (&mutex, NULL); /*定义*/
...
pthread_mutex_lock(&mutex); /*获取互斥锁*/
... /*临界资源*/
pthread_mutex_unlock(&mutex); /*释放互斥锁*/
如果一个线程已经给一个互斥量上锁了,后来在操作的过程中又再次调用了该上锁的操作,那么该线程将会无限阻塞在这个地方,从而导致死锁。这就需要互斥量的属性。
互斥量分为下面三种:
1、快速型。这种类型也是默认的类型。该线程的行为正如上面所说的。
2、递归型。如果遇到我们上面所提到的死锁情况,同一线程循环给互斥量上锁,那么系统将会知道该上锁行为来自同一线程,那么就会同意线程给该互斥量上锁。
3、错误检测型。如果该互斥量已经被上锁,那么后续的上锁将会失败而不会阻塞,pthread_mutex_lock()操作将会返回EDEADLK。
互斥量的属性类型为pthread_mutexattr_t。声明后调用pthread_mutexattr_init()来创建该互斥量。然后调用pthread_mutexattr_settype来设置属性。格式如下:int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
第一个参数attr,就是前面声明的属性变量;第二个参数kind,就是我们要设置的属性类型。他有下面几个选项:
PTHREAD_MUTEX_FAST_NP
PTHREAD_MUTEX_RECURSIVE_NP
PTHREAD_MUTEX_ERRORCHECK_NP
下面给出一个使用属性的简单过程:
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&mutex,&attr);
pthread_mutex_destroy(&attr);
前面我们提到在调用pthread_mutex_lock()的时候,如果此时mutex已经被其他线程上锁,那么该操作将会一直阻塞在这个地方。如果我们此时不想一直阻塞在这个地方,那么可以调用下面函数:pthread_mutex_trylock。
如果此时互斥量没有被上锁,那么pthread_mutex_trylock将会返回0,并会对该互斥量上锁。如果互斥量已经被上锁,那么会立刻返回EBUSY。
二、条件变量
需要的头文件:pthread.h
条件变量标识符:pthread_cond_t
1、互斥锁的存在问题:
互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。设想一种简单情景:多个线程访问同一个共享资源时,并不知道何时应该使用共享资源,如果在临界区里加入判断语句,或者可以有效,但一来效率不高,二来复杂环境下就难以编写了,这是我们需要一个结构,能在条件成立时触发相应线程,进行变量修改和访问。
2、条件变量:
条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。
3、条件变量的相关函数
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //条件变量结构
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t*cond_attr);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime);
int pthread_cond_destroy(pthread_cond_t *cond);
详细说明:
(1)创建和注销
条件变量和互斥锁一样,都有静态动态两种创建方式
a.静态方式
静态方式使用PTHREAD_COND_INITIALIZER常量,如下:
pthread_cond_t cond=PTHREAD_COND_INITIALIZER
b.动态方式
动态方式调用pthread_cond_init()函数,API定义如下:
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)
尽管POSIX标准中为条件变量定义了属性,但在LinuxThreads中没有实现,因此cond_attr值通常为NULL,且被忽略。
注销一个条件变量需要调用pthread_cond_destroy(),只有在没有线程在该条件变量上等待的时候才能注销这个条件变量,否则返回EBUSY。因为Linux实现的条件变量没有分配什么资源,所以注销动作只包括检查是否有等待线程。API定义如下:int pthread_cond_destroy(pthread_cond_t *cond)
(2)等待和激发
a.等待
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) //等待
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime) //有时等待
等待条件有两种方式:无条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEOUT,结束等待,其中abstime以与time()系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。
无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()(或 pthread_cond_timedwait(),下同)的竞争条件(Race Condition)。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开 pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。
b.激发
激发条件有两种形式,pthread_cond_signal()激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个;而pthread_cond_broadcast()则激活所有等待线程。
(3)其他操作
pthread_cond_wait ()和pthread_cond_timedwait()都被实现为取消点,因此,在该处等待的线程将立即重新运行,在重新锁定mutex后离开 pthread_cond_wait(),然后执行取消动作。也就是说如果pthread_cond_wait()被取消,mutex是保持锁定状态的,因而需要定义退出回调函数来为其解锁。
pthread_cond_wait实际上可以看作是以下几个动作的合体:
解锁线程锁;
等待条件为true;
加锁线程锁;
使用形式:
// 线程一代码
pthread_mutex_lock(&mutex);
if (条件满足)
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
// 线程二代码
pthread_mutex_lock(&mutex);
while (条件不满足)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
/*线程二中为什么使用while呢?因为在pthread_cond_signal和pthread_cond_wait返回之间,有时间差,假设在这个时间差内,条件改变了,显然需要重新检查条件。也就是说在pthread_cond_wait被唤醒的时候可能该条件已经不成立。*/
三、信号量
信号量其实就是一个计数器,也是一个整数。每一次调用wait操作将会使semaphore值减一,而如果semaphore值已经为0,则wait操作将会阻塞。每一次调用post操作将会使semaphore值加一。
需要的头文件:semaphore.h
信号量标识符:sem_t
主要函数:
(1)sem_init
功能: 用于创建一个信号量,并初始化信号量的值。
函数原型: int sem_init (sem_t* sem, int pshared, unsigned int value);
函数传入值: sem:信号量。
pshared:决定信号量能否在几个进程间共享。由于目前LINUX还没有实现进程间共享信息量,所以这个值只能取0。
value:初始计算器
函数返回值: 0:成功;-1:失败。
(2)其他函数。
//等待信号量
int sem_wait (sem_t* sem);
int sem_trywait (sem_t* sem);
//发送信号量
int sem_post (sem_t* sem);
//得到信号量值
int sem_getvalue (sem_t* sem);
//删除信号量
int sem_destroy (sem_t* sem);
功能:sem_wait和sem_trywait相当于P操作,它们都能将信号量的值减一,两者的区别在于若信号量的值小于零时,sem_wait将会阻塞进程,而sem_trywait则会立即返回。
sem_post相当于V操作,它将信号量的值加一,同时发出唤醒的信号给等待的进程(或线程)。
sem_getvalue 得到信号量的值。
sem_destroy 摧毁信号量。
使用形式:
sem_t sem;
sem_init(&sem, 0, 1); /*信号量初始化*/
...
sem_wait(&sem); /*等待信号量*/
... /*临界资源*/
sem_post(&sem); /*释放信号量*/
信号量与线程锁、条件变量相比还有以下几点不同:
1)锁必须是同一个线程获取以及释放,否则会死锁。而条件变量和信号量则不必。
2)信号的递增与减少会被系统自动记住,系统内部有一个计数器实现信号量,不必担心会丢失,而唤醒一个条件变量时,如果没有相应的线程在等待该条件变量,这次唤醒将被丢失。
发表评论
-
睡眠和休眠有什么区别?
2012-12-08 01:01 1167到底用睡眠和休眠, ... -
什么是watchdog + 为何在要系统初始化的时候关闭watchdog
2012-12-06 17:09 1537什么是watchdog + 为何在要系统初始化的时候关闭wat ... -
MMU结构以及工作原理
2012-11-25 00:15 1367MMU的大名,早就听说了,可是一直不知道它是怎么工作的,前几月 ... -
Thread-Specific Data 注:相当于线程内的全局变量,可减少线程内调用其他函数的变量数
2012-11-18 01:20 1403Linux多线程编程中引入了Thread-Specific D ... -
linux下socket编程实例
2012-11-13 12:03 820一、基本socket函数Linux系统是通过提供套接字( ... -
简单的RPC编程实践——HelloWorld的实现
2012-11-13 01:39 1724近期课程的作业需要 ... -
Linux模块编程
2012-11-10 12:38 606Linux模块简介 首先这个module不同于m ... -
这场官司让BSD错过了机会,让linux在应用广泛度上超越了它
2012-11-10 00:50 120270年代末,在Unix发展到 ... -
printk与syslog(至少在Redhat中是这样的)+Ubuntu下用最简单的读到/proc/kmsg
2012-10-12 01:00 1433在头文件 <linux/kerne ... -
关于Linux的syslog
2012-10-12 00:59 1122内核中printk发出的消息是这样传递到用户空间的。 ... -
LINUX下三个内核文件详解
2012-10-11 23:45 753在网络中,不少服务器采用的是Linux系统。为了进一步提高服务 ... -
Linux 2.6.32的内核栈和用户空间栈关系
2012-10-01 00:26 1039.进程的堆栈 内核在 ... -
Linux 内核堆栈
2012-10-01 00:25 1098所有进程(包括内核进程和普通进程)都有一个内核栈,在x8 ... -
linux内核栈与用户栈
2012-10-01 00:24 1279http://19880512.blog.51cto.c ... -
Debian 6 驱动开发环境搭建
2012-09-29 15:33 1569Debian 6 驱动开发环境搭建1.安装相关工具apt-ge ... -
linux-kernel mail list订阅
2012-09-28 12:02 1441由于linux-kernel 的mail list中邮件 ... -
unix Mechanism vs Policy(机制与策略)
2012-09-27 13:12 2566http://blog.csdn.net/ostrichmys ... -
Linux 最简单的驱动程序hello world
2012-09-26 23:27 1432http://blog.sina.com.cn/s/bl ... -
编译linux驱动方法
2012-09-26 23:10 707最近在学习linux的驱动,之前做嵌入式实验的时候加载驱 ... -
Linux设备号,主设备号,次设备号
2012-09-26 22:48 1591Linux的设备管理是和文件系统紧密结合的,把设备和文件关联起 ...
相关推荐
Linux 互斥锁、条件变量和信号量 在 Linux 多线程编程中,为了防止多个线程同时访问共享资源,Linux 提供了互斥锁、条件变量和信号量来保护共享资源。 一、互斥锁 互斥锁是一种信号量,常用来防止两个进程或线程...
- 服务端创建共享内存,初始化互斥锁和条件变量。 - 客户端连接共享内存,获取互斥锁,读写数据,然后释放锁。 - 当数据满足特定条件时,服务端或客户端可以发送信号量通知对方,通过条件变量进行同步。 5. **...
在给定的`server.c`和`client.c`代码中,服务器进程可能会创建一块共享内存,设置互斥锁和条件变量,然后在其中存储数据。客户端进程则通过连接共享内存,使用互斥锁保护数据,当数据满足预设条件时,服务器进程会...
除了互斥锁,Linux还提供了信号量(Semaphore)、条件变量(Condition Variable)等同步机制,可以根据不同的应用场景选择合适的方法。 总之,互斥锁是保证多线程并发环境下数据安全的重要工具,通过理解其原理和...
在Linux系统中,多线程编程是实现并发执行的关键技术,而互斥锁(mutexes)、条件变量(condition variables)和信号量(semaphores)是确保线程安全和资源同步的重要工具。以下是对这些概念的详细解释: 1. 互斥锁...
在Linux中,信号量可以分为两种类型:整型信号量(互斥锁)和记录型信号量(可以有多个等待进程)。在本实例中,使用的是整型信号量,它用于实现进程互斥。 【进程互斥】进程互斥是指在同一时间只有一个进程可以...
3. **互斥锁的概念与实现**:在多进程环境中,互斥锁是一种通过信号量实现的机制,确保同一时间只有一个进程访问特定资源。当一个进程获得锁后,其他试图获取该锁的进程将被阻塞,直到锁被释放。 4. **PV操作**:...
在POSIX标准下,Linux提供了两种信号量实现方式:无名信号量和命名信号量。 - **无名信号量**主要用于同一进程内的线程间通信,它们共享相同的内存空间,因此无需额外的标识符。初始化无名信号量使用`sem_init`函数...
在Linux中,信号量有两种类型:互斥量(互斥锁)和计数信号量。互斥量只允许一个进程访问资源,而计数信号量可以控制同时访问资源的进程数量。`semget`用于创建信号量集,`semop`执行信号量操作(如P(等待)和V...
它是一个整型变量,可以用来计数,也可以作为互斥锁。在多线程或多进程中,当一个进程修改了共享资源后,可以通过减信号量来表示资源已被占用;而其他试图访问该资源的进程则会通过尝试加信号量来获取权限,如果信号...
4. 定义了生产者和消费者进程,并使用信号量和互斥锁来实现缓冲池的访问控制。 实验代码 实验代码使用C语言编写,使用了pthread库和semaphore库来实现线程同步和信号量操作。代码中定义了生产者和消费者进程,并...
信号量有两种基本类型:二进制信号量和计数信号量。二进制信号量只有0和1两个状态,相当于互斥锁,用于确保对资源的独占访问。而计数信号量可以是任何非负值,它可以表示更多的资源状态,类似于条件变量,但使用起来...
在Linux系统中,线程管理是程序设计的关键部分,特别是在多任务环境中,为了确保程序的稳定性和高效性,程序员常使用互斥量和条件变量来控制线程的并发执行。互斥量是一种同步机制,用于保护共享资源免受并发访问,...
本示例通过信号量和共享内存这两种IPC机制,展示了如何在多个进程中有效地协同工作。信号量用于同步对共享资源的访问,而共享内存则提供了进程间直接读写的共享数据区域。 信号量是一种同步机制,它是一个整型变量...
计数信号量可以是任意非负值,更灵活,可以模拟条件变量的行为,有时甚至比条件变量更简洁。 在Linux中,信号量可以是命名的或未命名的。未命名信号在进程内存中创建,可能通过`fork()`继承,也可通过文件系统权限...
同步和互斥在多进程中主要通过信号量和消息队列等机制实现。 二、多线程 多线程则是在一个进程中创建多个执行流,它们共享同一块内存空间,资源利用率高,但数据同步和互斥问题更复杂。在Linux中,可以使用`...
在Linux内核中,有互斥锁(mutex)和普通信号量(semaphore)两种类型。互斥锁仅允许单个线程访问资源,而信号量可以控制多个线程同时访问,但不超过其值。 在Zynq的Linux驱动中,当多个设备请求共享硬件资源,如I/...