b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

[Linux多线程同步机制]

电脑杂谈  发布时间:2020-04-21 22:32:30  来源:网络整理

进程 线程 linux_linux进程与线程_linux多线程

一个,互斥锁

尽管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常量,如下所示:

进程 线程 linux_linux进程与线程_linux多线程

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”,

linux进程与线程_进程 线程 linux_linux多线程

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);

进程 线程 linux_linux进程与线程_linux多线程

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海里内

    • 李峤
      李峤

      舰载武器质量和威力也很重要

    • 矢作纱友里
      矢作纱友里

      容许现在打击的红灯区的存在

    热点图片
    拼命载入中...