首页>>科技 >>内容

linux中多线程编程的知识点有哪些,Linux中多线程编程的知识点

发布时间:2023-07-15 15:22:12编辑:温柔的背包来源:

很多朋友对linux中多线程编程的知识点有哪些,Linux中多线程编程的知识点不是很了解,每日小编刚好整理了这方面的知识,今天就来带大家一探究竟。

linux中多线程编程的知识点有哪些,Linux中多线程编程的知识点

大家好,大家好,我是穆蓉,今天我们继续讲Linux中多线程编程的重要知识点,详细讲讲多线程中的同步和互斥机制。

同步与互斥:多线程中的互斥是指当多个线程访问同一个资源时,只允许一个线程同时访问,具有唯一性、排他性。但互斥不能限制访问者访问资源的顺序,即访问是乱序的;同步:多线程同步是指访问者通过其他机制访问时在互斥的基础上(大多数情况)对资源进行排序。在大多数情况下,同步已经实现了互斥,特别是对资源的所有写入都必须是互斥的。在极少数情况下,可以允许多个访问者同时访问资源。在多任务操作系统中,同时运行的多个任务可能都需要使用相同的资源。为了一次只允许一个任务访问资源,需要使用互斥体来保护资源。互斥体是一种简单的锁定方法,用于控制对共享资源的访问。互斥锁只有两种状态,即锁定(lock)和解锁(unlock)。

互斥量操作的基本流程访问共享资源之前,锁定互斥量锁定之后,访问共享资源访问共享资源之后,解锁互斥量锁定互斥量之后,任何其他尝试再次锁定互斥量的线程都会被阻塞,直到锁被释放`

互斥量具有原子性:互斥量是一种原子操作。操作系统保证如果一个线程锁定了互斥锁,其他线程不会同时成功锁定该互斥锁。唯一性:如果一个线程锁定了一个互斥锁,在它被解锁之前,其他线程无法锁定该互斥锁非忙等待:如果一个线程已经锁定了一个互斥锁,而第二个线程尝试锁定该互斥锁,则第一个线程的两个线程将被挂起,不占用任何CPU资源,直到第一个线程解锁互斥锁,第二个线程将被唤醒并继续执行,同时锁定互斥锁示例#include # include #include #include #include char *pTestBuf=nullptr; //全局变量pthread_mutex_t mutex;void *ThrTestMutex(void *p){ pthread_mutex_lock(mutex); //锁{ pTestBuf=( char*)p;睡眠(1); pthread_mutex_unlock(互斥体); //解锁}int main(){ pthread_mutex_init(mutex, NULL); pthread_t tid1, tid2; pthread_create(tid1, NULL, ThrTestMutex, (void *)'Thread1'); pthread_create(tid2, NULL, ThrTestMutex, (void *)'Thread2'); pthread_join(tid1, NULL); pthread_join(tid2, NULL); pthread_mutex_destroy(mutex); return 0;} 读写锁读写锁允许更高的并行性,也称为共享互斥锁。互斥体要么被锁定,要么被解锁,并且一次只有一个线程可以锁定它。读写锁可以有三种状态:读模式下的锁定状态、写模式下的锁定状态和解锁状态。写模式下只能有一个线程占用读写锁,而读模式下可以多个线程同时占用读写锁,即允许多个线程读,但只允许一个线程写。

当读操作较多、写操作较少时,可以使用读写锁来提高线程读并发性。读写锁特性如果有线程读取数据,则允许其他线程执行读操作,但不允许执行写操作。如果有线程在写数据,则不允许其他线程进行读写操作。如果一个线程申请了读锁,其他线程可以申请读锁,但不能申请写锁。如果一个线程申请了写锁,其他线程就不能申请读锁,也不能申请写锁。读写锁适用于数据读取次数远高于写入次数的情况。读写锁的创建和销毁#include int phtread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);参数:rwlock:读写锁,attr:读写锁属性返回值:成功返回0,错误返回错误码读写锁lock unlock #include /** 添加读锁*/int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) ;/** 添加写锁*/int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); /** 释放锁*/int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);参数: rwlock:读写锁返回值:成功返回0;错误,返回错误码示例#include #include #include #include #include pthread_rwlock_t rwlock;int g_nNum=0;void *fun1(void *arg) { while(1) { pthread_rwlock_rdlock(rwlock); { printf('读取线程1==%d\\n', g_nNum); pthread_rwlock_unlock(rwlock);睡眠(1); }} void *fun2(void *arg){ while(1) { pthread_rwlock_rdlock(rwlock); { printf('读取线程2==%d\\n ', g_nNum); pthread_rwlock_unlock(rwlock);睡眠(1); }} void *fun3(void *arg){ while(1) { pthread_rwlock_wrlock( rwlock); { g_nNum++; printf('写入线程1\\n'); pthread_rwlock_unlock(rwlock);睡眠(1); }} void *fun4 (void *arg){ while(1) { pthread_rwlock_wrlock(rwlock); { g_nNum++; printf('写入线程2\\n'); pthread_rwlock_unlock(rwlock);睡眠(1); int main(int arc, char *argv[]) { pthread_t ThrId1, ThrId2, ThrId3, ThrId4; pthread_rwlock_init(rwlock, NULL); //初始化读写锁pthread_create(ThrId1, NULL, fun1, NULL); pthread_create( ThrId2, NULL, fun2, NULL); pthread_create(ThrId3, NULL, fun3, NULL); pthread_create(ThrId4, NULL, fun4, NULL); pthread_join(ThrId1, NULL); pthread_join(ThrId2, NULL); pthread_join(ThrId3, NULL); pthread_join(ThrId4, NULL); pthread_rwlock_destroy(rwlock); //销毁读写锁return 0; }结果

自旋锁自旋锁与互斥锁具有相同的功能。唯一的区别是互斥锁阻塞时不占用CPU,而自旋锁阻塞后不会让出CPU。它会一直忙等待,直到获得锁自旋锁。在用户态很少使用,但在内核态使用自旋锁较多:锁持有时间比较短,或者说小于2次上下文切换次数。自旋锁用于用户态函数接口和交互斥力是一样的,将pthread_mutex_lock()/pthread_mutex_unlock()中的互斥量替换为spin,如:pthread_spin_init() spinlock函数linux中的自旋锁用结构体spinlock_t表示,它在include/linux/spinlock_type.h 中定义。自旋锁的接口函数全部定义在include/linux/spinlock.h头文件中。实际使用时只需要包含它即可。该示例包含条件变量,用于阻塞线程,直到条件发生。通常条件变量和互斥体是同时使用的。条件变量允许线程休眠,等待满足某些条件。条件变量是一种使用线程之间共享的全局变量进行同步的机制。条件变量的逻辑:一个线程挂起等待条件变量的条件为真,另一个线程使条件为真。基本原理线程在更改条件状态之前锁定互斥体。如果条件为假,线程会自动阻塞并释放等待状态改变的互斥体。如果另一个线程更改了条件,它会向关联的条件变量发出信号,唤醒一个或多个等待它的线程。如果两个进程共享可读写内存,可以使用条件变量来实现两个进程之间的线程同步

例如#include #include #include #include pthread_cond_t Taxicond=pthread_cond_initializer; pthread_mutex_t 出租车互斥体=pthread_mutex_initiali Zer; void *Thrfun1 (void *name) {char *p=(char *) name; //锁定,将信号量添加到队列中,释放信号量pthread_mutex_lock(taximutex); { pthread_cond_wait(taxicond,taximutex); pthread_mutex_unlock(taximutex); printf ('ThrFun1: %s 现在收到信号了!\\n', p); pthread_exit(NULL); } void *ThrFun 2( void *name) { char *p=(char *)name; printf('ThrFun2: %s cond 信号。\\n', p); //信号pthread_cond_signal(taxicond); pthread_exit(NULL); } int main ( int argc, char **argv) { pthread_t 线程1, 线程2; pthread_attr_t 线程属性; pthread_attr_init(threadattr); //线程属性初始化//创建三个线程pthread_create(Thread1, threadattr, ThrFun1, (void *)'Thread1');睡眠(1); pthread_create(Thread2, threadattr, ThrFun2, (void *)'Thread2');睡眠(1); pthread_join(线程1, NULL); pthread_join(线程2, NULL);返回0; }结果

虚假唤醒当线程从等待有信号的条件变量中唤醒时,却发现其等待的条件未得到满足,就会发生虚假唤醒。之所以称为虚假,是因为该线程似乎无缘无故地被唤醒。但虚假唤醒不会无缘无故地发生:它们通常是因为在发出条件变量信号和等待线程最终运行之间,另一个线程运行并更改条件以避免虚假唤醒。在wait方面,我们要把判断条件和wait()结合起来放到while循环中pthread_mutex_lock(taximutex); { while(value !=WantValue) { pthread_cond_wait(taxicond,taximutex); pthread_mutex_unlock(taximutex);信号量信号量用于进程或线程之间的同步和互斥。数量本质上是一个非负整数计数器,用于控制对公共资源的访问。编程时可以根据信号量值的操作结果来判断是否可以访问公共资源。当信号量值大于0时才可以访问,否则会阻塞#include //初始化信号量int sem_init(sem_t *sem, int pshared, unsigned int value);//信号量P操作(减1) int sem_wait(sem_t *sem);//以非阻塞的方式对信号量进行减1操作int sem_trywait(sem_t *sem);//信号量V操作(加1) int sem_post(sem_t *sem);//获取值信号量的int sem_getvalue(sem_t *sem, int *sval);//销毁信号量int sem_destroy(sem_t *sem);示例//信号量用于同步实例#include #include #include #include sem_t sem_g, SEM_P; //定义两个信号量char s8Test='a'; void *pthread_g(void *arg) //本线程改变字符的值{ while(1) { sem_wait(sem_g); s8测试++;睡眠(2); sem_post(sem_p); }} void *pthread_p(void *arg) //该线程打印字符的值{ while(1) { sem_wait(sem_p ); printf('%c',s8Test); fflush(标准输出); sem_post(sem_g); }} int main(int argc, char *argv[]){ pthread_t tid1,tid2; sem_init(sem_g, 0, 0) ; //将信号量初始化为0 sem_init(sem_p, 0, 1); //将信号量初始化为1 pthread_create(tid1, NULL, pthread_g, NULL); pthread_create(tid2, NULL, pthread_p, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL);返回0; } 结果

结论好了,通过这篇文章,希望对朋友们有所帮助,也希望能够对多线程编程方面的知识有更深入的了解。

以上知识分享希望能够帮助到大家!