
一个,互斥锁
尽管Posix Thread也可以使用IPC的信号量机制来实现互斥锁的互斥锁功能,但是很明显,semphore的功能太强大了. 在Posix Thread中,定义了另一组专门用于线程同步的互斥函数.
1. 创建并销毁
有两种创建互斥量的方法: 静态和动态.
POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,如下所示: pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER;在LinuxThreads的实现中,pthread_mutex_t是结构,而PTHREAD_MUTEX_INITIALIZER是结构常量.
动态方式是使用pthread_mutex_init()函数初始化互斥量. 该API的定义如下: int pthread_mutex_init(pthread_mutex_t *互斥体,const pthread_mutexattr_t *互斥体),其中,mutexattr用于指定互斥体属性(请参见下文),如果为NULL,则使用默认属性.
pthread_mutex_destroy()用于取消互斥锁. 该API的定义如下: int pthread_mutex_destroy(pthread_mutex_t *互斥锁)销毁互斥锁意味着释放它占用的资源并要求该锁当前处于打开状态. 由于互斥锁在Linux中不占用任何资源,因此LinuxThreads中的pthread_mutex_destroy()除了检查锁定状态(锁定状态返回EBUSY)外没有其他动作.
2. 互斥锁定属性
创建锁时将指定互斥锁的属性. LinuxThreads实现中只有一个锁类型属性. 尝试添加锁定的互斥锁时,不同的锁定类型会表现不同. 当前(glibc2.2.3,linuxthreads0.9)有四个值可供选择:
PTHREAD_MUTEX_TIMED_NP,这是默认值,即普通锁. 锁定线程后,请求锁定的其余线程将形成等待队列,并在解锁后根据优先级获得锁定. 这种锁定策略可确保资源分配的公平性.
PTHREAD_MUTEX_RECURSIVE_NP是一个嵌套锁,它允许同一线程多次成功获取同一锁,并通过多次解锁将其解锁. 如果是来自其他线程的请求,请在解锁锁定线程时重新竞争.
PTHREAD_MUTEX_ERRORCHECK_NP,错误检查锁,如果同一线程请求相同的锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型的操作相同. 这样可以确保在不允许多个锁时,在最简单的情况下也不会发生死锁.
PTHREAD_MUTEX_ADAPTIVE_NP,适用于锁(最简单的锁类型),仅等待解锁并重新竞争.
3. 锁定操作
锁定操作主要包括锁定pthread_mutex_lock(),解锁pthread_mutex_unlock()和测试锁定pthread_mutex_trylock(). 无论哪种类型的锁,两个不同的线程都不可能同时获得它,而您必须等待unlock. 对于普通锁和自适应锁类型,解锁器可以是同一进程中的任何线程. 错误检测锁必须由储物柜解锁才能生效,否则返回EPERM;对于嵌套锁,文档和实现要求必须由Unlocked锁定,但实验结果表明没有这种限制,并且这种差异尚未得到解释. 如果锁定后未解锁同一进程中的线程,则其他线程将无法获得该锁定.
int pthread_mutex_lock(pthread_mutex_t *互斥锁)
int pthread_mutex_unlock(pthread_mutex_t *互斥锁)
int pthread_mutex_trylock(pthread_mutex_t *互斥锁)
pthread_mutex_trylock()的语义与pthread_mutex_lock()相似,不同之处在于返回EBUSY而不是在锁已被占用时等待.
4. 其他
POSIX线程锁定机制的Linux实现不是取消点,因此linux多线程,延迟取消类型的线程不会由于取消信号而使锁定处于等待状态. 值得注意的是,如果线程在锁定之后在解锁之前被取消,则锁定将始终保持锁定状态,因此,如果关键部分中有取消点,或者如果设置了异步取消类型,则必须在出口中将其解锁回调函数.
同时,这种锁定机制也不是异步信号安全的,也就是说,在信号处理过程中不应该使用互斥锁,否则很容易造成死锁.
第二个条件变量
条件变量是一种用于与线程之间共享的全局变量进行同步的机制. 它们主要包括两个动作: 一个线程在等待条件变量的条件建立时挂起;另一个线程建立要建立的条件(给出一个有条件的建立信号). 为了防止竞争,条件变量的使用总是与互斥锁结合使用.
1. 创建并注销
像条件变量和互斥锁一样,有两种创建静态和动态的方法,静态方法使用PTHREAD_COND_INITIALIZER常量,如下所示:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER
pthread_cond_init()函数被动态调用,API定义如下:
int pthread_cond_init(pthread_cond_t * cond,pthread_condattr_t * cond_attr)
尽管在POSIX标准中为条件变量定义了属性linux多线程,但是它们并未在LinuxThreads中实现,因此cond_attr的值通常为NULL,并且被忽略.
要取消条件变量,您需要调用pthread_cond_destroy(). 仅当没有线程等待条件变量时,才可以取消条件变量,否则它将返回EBUSY. 由于Linux实现的条件变量不分配任何资源,因此注销操作仅包括检查是否有等待线程. API定义如下:
int pthread_cond_destroy(pthread_cond_t * cond)
2. 等待并刺激
int pthread_cond_wait(pthread_cond_t * cond,pthread_mutex_t *互斥锁)
int pthread_cond_timedwait(pthread_cond_t * cond,pthread_mutex_t *互斥量,const struct timespec * abstime)
有两种等待条件的方法: 无条件等待pthread_cond_wait()和时间等待pthread_cond_timedwait(). 在时间等待模式下,如果在给定时间之前未满足条件,则返回ETIMEOUT结束等待,其中abstime等于time(). 系统调用以绝对时间的形式出现,具有相同的含义. 0表示1970年1月1日格林尼治标准时间0: 00: 00:00.
无论哪种等待方式,都必须与互斥锁一起使用,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait(),以下相同)的竞争条件. 互斥锁互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或自适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),并且必须在调用pthread_cond_wait()之前被此线程(pthread_mutex_lock())锁定,并且在更新条件等待队列之前,互斥锁将保持锁定状态状态,然后程挂起等待之前解锁. 在满足条件并离开pthread_cond_wait()之前,互斥锁将重新锁定以与锁定操作相对应,然后再输入pthread_cond_wait().
有两种形式的射击条件. pthread_cond_signal()激活一个等待条件的线程. 当有多个等待线程时,其中一个按入队顺序被激活;和pthread_cond_broadcast()激活所有等待的线程.
3. 其他
Pthread_cond_wait()和pthread_cond_timedwait()都被实现为取消点,因此在那里等待的线程将立即重新运行,在重新锁定互斥锁之后离开pthread_cond_wait(),然后执行取消操作. 也就是说,如果取消了pthread_cond_wait(),则互斥锁将保持锁定状态,因此您需要定义退出回调函数以对其进行解锁.
以下示例着重于互斥锁和条件变量的组合使用,以及取消对条件等待动作的影响. 在该示例中,两个线程被启动并等待相同的条件变量. 如果不使用退出回调函数(请参见示例中的注释部分),则tid2将永久在pthread_mutex_lock()中等待. 如果使用了回调函数,则tid2的条件等待和主线程的条件激发都可以正常工作.
#include
#include
#include
pthread_mutex_t互斥锁;
pthread_cond_t cond;
void * child1(void * arg)
{
pthread_cleanup_push(pthread_mutex_unlock和互斥锁); / *评论1 * /
同时(1){
printf(“线程1开始运行\ n”);
printf(“线程1 pthread_mutex_lock返回%d \ n”,

pthread_mutex_lock(&mutex));
pthread_cond_wait(&cond,&Mutex);
printf(“应用了线程1条件\ n”);
pthread_mutex_unlock(&mutex);
睡眠(5);
}
pthread_cleanup_pop(0); / *评论2 * /
}
void * child2(void * arg)
{
同时(1){
睡眠(3); / *评论3 * /
printf(“线程2开始运行. \ n”);
printf(“线程2 pthread_mutex_lock返回%d \ n”,
pthread_mutex_lock(&mutex));
pthread_cond_wait(&cond,&Mutex);
printf(“应用了线程2条件\ n”);
pthread_mutex_unlock(&mutex);
睡眠(1);
}
}
int主(无效)
{
int tid1,tid2;
printf(“您好,条件变量测试\ n”);
pthread_mutex_init(&互斥锁,NULL);

pthread_cond_init(&cond,NULL);
pthread_create(&tid1,NULL,child1,NULL);
pthread_create(&tid2,NULL,child2,NULL);
做{
睡眠(2); / *评论4 * /
pthread_cancel(tid1); / *评论5 * /
睡眠(2); / *评论6 * /
pthread_cond_signal(&cond);
}而(1);
睡眠(100);
pthread_exit(0);
}
如果不执行注释5的pthread_cancel()操作,即使没有sleep()延迟操作,child1和child2也可以正常工作. 注释3和注释4中的延迟使child1有时间完成取消操作,因此child2可以在child1退出后进入请求锁定操作. 如果在注释1和注释2中未定义回调函数,则系统将在child2请求锁定的位置挂起;否则,系统将挂起. 并且如果注释3和注释4都没有同时延迟,则可以在child1完成取消动作之前控制child2,因此成功执行了申请锁的操作,但是由于存在该操作,它可能被挂起在pthread_cond_wait()中也是申请互斥锁的操作. child1函数提供标准的条件变量用法: 回调函数保护,在等待条件之前锁定以及在pthread_cond_wait()返回之后解锁.
条件变量机制不是异步信号安全的,也就是说,在信号处理函数中调用pthread_cond_signal()或pthread_cond_broadcast()可能会导致死锁.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-184064-1.html
舰载武器质量和威力也很重要
容许现在打击的红灯区的存在
国际上争当雷锋
只要进我岛12海里内