今天我们来聊一聊Linux中多线程编程中的重要知识点,详细谈谈多线程中同步和互斥机制。
一、同步和互斥二、互斥锁
在多任务操作系统中,同时运行的多个任务可能都需要使用同一种资源。为了同一时刻只允许一个任务访问资源,需要用互斥锁对资源进行保护。互斥锁是一种简单的加锁的方法来控制对共享资源的访问,互斥锁只有两种状态,即上锁( lock )和解锁( )。
互斥锁操作基本流程
访问共享资源前,对互斥锁进行加锁
完成加锁后访问共享资源
对共享资源完成访问后,对互斥锁进行解锁
对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放
互斥锁特性示例
#include
#include
#include
#include
#include
char *pTestBuf = nullptr; // 全局变量
/* 定义互斥锁 */
pthread_mutex_t mutex;
void *ThrTestMutex(void *p)
{
pthread_mutex_lock(&mutex); // 加锁
{
pTestBuf = (char*)p;
sleep(1);
}
pthread_mutex_unlock(&mutex); // 解锁
}
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;
}
三、读写锁读写锁特性
如果有线程读数据,则允许其它线程执行读操作,但不允许写操作
如果有线程写数据,则其它线程都不允许读、写操作
如果某线程申请了读锁,其它线程可以再申请读锁,但不能申请写锁
如果某线程申请了写锁linux多线程编程,其它线程不能申请读锁,也不能申请写锁
读写锁适合于对数据的读次数比写次数多得多的情况
读写锁创建和销毁
#include
int phtread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
读写锁加锁解锁
#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);
示例
#include
#include
#include
#include
#include
/* 定义读写锁 */
pthread_rwlock_t rwlock;
/* 定义共享资源变量 */
int g_nNum = 0;
/* 读操作 其他线程允许读操作 不允许写操作 */
void *fun1(void *arg)
{
while(1)
{
pthread_rwlock_rdlock(&rwlock);
{
printf("read thread 1 == %dn", g_nNum);
}
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
}
/* 读操作,其他线程允许读操作,不允许写操作 */
void *fun2(void *arg)
{
while(1)
{
pthread_rwlock_rdlock(&rwlock);
{
printf("read thread 2 == %dn", g_nNum);
}
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
}
/* 写操作,其它线程都不允许读或写操作 */
void *fun3(void *arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock);
{
g_nNum++;
printf("write thread 1n");
}
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
}
/* 写操作,其它线程都不允许读或写操作 */
void *fun4(void *arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock);
{
g_nNum++;
printf("write thread 2n");
}
pthread_rwlock_unlock(&rwlock);
sleep(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;
}
四、自旋锁自旋锁函数示例
include
spinlock_t lock; //定义自旋锁
spin_lock_init(&lock); //初始化自旋锁
spin_lock(&lock); //获得锁,如果没获得成功则一直等待
{
....... //处理临界资源
}
spin_unlock(&lock); //释放自旋锁
五、条件变量基本原理
线程在改变条件状态之前先锁住互斥量。如果条件为假,线程自动阻塞,并释放等待状态改变的互斥锁。如果另一个线程改变了条件linux多线程编程,它发信号给关联的条件变量,唤醒一个或多个等待它的线程。如果两进程共享可读写的内存,条件变量可以被用来实现这两进程间的线程同步
示例
#include
#include
#include
#include
pthread_cond_t taxicond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t taximutex = PTHREAD_MUTEX_INITIALIZER;
void *ThrFun1(void *name)
{
char *p = (char *)name;
// 加锁,把信号量加入队列,释放信号量
pthread_mutex_lock(&taximutex);
{
pthread_cond_wait(&taxicond, &taximutex);
}
pthread_mutex_unlock(&taximutex);
printf ("ThrFun1: %s now got a signal!n", p);
pthread_exit(NULL);
}
void *ThrFun2(void *name)
{
char *p = (char *)name;
printf ("ThrFun2: %s cond signal.n", p); // 发信号
pthread_cond_signal(&taxicond);
pthread_exit(NULL);
}
int main (int argc, char **argv)
{
pthread_t Thread1, Thread2;
pthread_attr_t threadattr;
pthread_attr_init(&threadattr); // 线程属性初始化
// 创建三个线程
pthread_create(&Thread1, &threadattr, ThrFun1, (void *)"Thread1");
sleep(1);
pthread_create(&Thread2, &threadattr, ThrFun2, (void *)"Thread2");
sleep(1);
pthread_join(Thread1, NULL);
pthread_join(Thread2, NULL);
return 0;
}
虚假唤醒避免虚假唤醒
pthread_mutex_lock(&taximutex);
{
while(value != wantValue)
{
pthread_cond_wait(&taxicond, &taximutex);
}
}
pthread_mutex_unlock(&taximutex);
六、信号量
#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);
s8Test++;
sleep(2);
sem_post(&sem_p);
}
}
void *pthread_p(void *arg) //此线程打印字符的值
{
while(1)
{
sem_wait(&sem_p);
printf("%c",s8Test);
fflush(stdout);
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);
return 0;
}
七、结束语
END
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。