目录
线程互斥概念
在计算机程序中,线程互斥是指多个线程尝试访问共享资源时出现冲突的情况。
例如,当两个线程同时尝试写入同一内存位置时,由于同时进行写入可能会导致数据的不一致性,因此需要确保只有一个线程能够访问该内存位置。
为了避免这种冲突,通常使用互斥锁(mutex)来实现线程互斥。互斥锁是一种同步原语,它可以确保在任何时刻只有一个线程能够访问共享资源。当一个线程需要访问共享资源时,它会尝试获取互斥锁。如果锁已经被另一个线程持有,那么该线程会被阻塞直到锁被释放。当持有锁的线程完成对共享资源的访问后,它会释放互斥锁,允许其他线程继续访问共享资源。
通过使用互斥锁,程序可以确保在任何时刻只有一个线程能够访问共享资源。
互斥专业词语
临界区:指的是一个访问共享资源的程序片段
互斥:多个线程在访问临界资源时,同一时间只能一个线程访问
互斥锁:通过互斥锁可以实现互斥机制,主要用来保护临界资源,每个临界资源都由一个互斥锁来保护,线程必须先获得互斥锁才能访问临界资源,访问完资源后释放该锁。如果无法获得锁,线程会阻塞直到获得锁为止。
函数接口
初始化互斥锁
int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
功能:初始化互斥锁
参数:mutex:互斥锁
attr: 互斥锁属性 // NULL表示缺省属性
返回值:成功 0
失败 -1
添加锁
int pthread_mutex_lock(pthread_mutex_t *mutex)
功能:申请互斥锁
参数:mutex:互斥锁
返回值:成功 0
失败 -1
注意:pthread_mutex_lock是阻塞的。
解开锁
int pthread_mutex_unlock(pthread_mutex_t *mutex)
功能:释放互斥锁
参数:mutex:互斥锁
返回值:成功 0
失败 -1
销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex)
功能:销毁互斥锁
参数:mutex:互斥锁
一个简单的使用互斥锁实现互斥程序
、
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int i = 0;
int arr[5] = {1, 2, 3, 4, 5};
pthread_mutex_t lock_t;
void *handly1(void *arg)
{
while (1)
{
pthread_mutex_lock(&lock_t);
puts("1");
sleep(1);
puts("2");
sleep(1);
puts("3");
sleep(1);
pthread_mutex_unlock(&lock_t);
}
}
void *handly2(void *arg)
{
while (1)
{
pthread_mutex_lock(&lock_t);
puts("子线程1");
sleep(1);
puts("子线程2");
pthread_mutex_unlock(&lock_t);
}
}
int main(int argc, char const *argv[])
{
if (pthread_mutex_init(&lock_t, NULL) != 0)
{
perror("mutex_init err.");
return -1;
}
pthread_t pid1;
if (pthread_create(&pid1, NULL, handly1, NULL) != 0)
{
perror("create err.");
return -1;
}
pthread_t pid2;
if (pthread_create(&pid2, NULL, handly2, NULL) != 0)
{
perror("create err.");
return -1;
}
pthread_join(pid1, NULL);
pthread_join(pid2, NULL);
return 0;
}
因为添加了互斥锁当handly1运行的时候,handly2无法运行;可自己运行观测下(建议观测久一点,因为互斥有随机性,不是按照约定来)
条件变量实现线程同步机制
在多线程编程中,条件变量是一种线程间同步的机制,它允许一个线程等待另一个或多个线程满足某个条件后再执行。条件变量通常与锁结合使用,以实现线程间的安全通信和互斥操作。
条件变量函数接口
初始化条件变量
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
功能:初始化条件变量
参数:cond:是一个指向结构pthread_cond_t的指针
restrict attr:是一个指向结构pthread_condattr_t的指针,一般设为NULL
返回值:成功:0 失败:非0
等待条件变量的产生
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
功能:等待条件的产生
参数:restrict cond:要等待的条件
restrict mutex:对应的锁
返回值:成功:0,失败:不为0
注意:等待是阻塞的等待,同时会将锁解开;当等到条件的时候, pthread_cond_wait会结束阻塞同时再次上锁。
产生条件变量
int pthread_cond_signal(pthread_cond_t *cond);
功能:产生条件变量
参数:cond:条件变量值
返回值:成功:0,失败:非0
注意:必须先pthread_cond_wait等待后,再触发pthread_cond_signal才会生效,单独的的触发pthread_cond_signal是没用的。
条件变量销毁
int pthread_cond_destroy(pthread_cond_t *cond);
功能:将条件变量销毁
参数:cond:条件变量值
返回值:成功:0, 失败:非0
条件变量代码实例
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int i = 0;
int arr[5] = {1, 2, 3, 4, 5};
pthread_mutex_t lock_t;
pthread_cond_t cond;
void *handly1(void *arg)
{
while (1)
{
sleep(1);
pthread_mutex_lock(&lock_t);
pthread_cond_signal(&cond);
puts("1");
sleep(1);
puts("2");
sleep(1);
puts("3");
sleep(1);
pthread_cond_wait(&cond,&lock_t);//若是阻塞,程序就什么都干不了,一直阻塞
pthread_mutex_unlock(&lock_t);
}
}
void *handly2(void *arg)
{
while (1)
{
pthread_mutex_lock(&lock_t);
pthread_cond_signal(&cond);
puts("子线程1");
sleep(1);
puts("子线程2");
pthread_cond_wait(&cond,&lock_t);
pthread_mutex_unlock(&lock_t);
}
}
int main(int argc, char const *argv[])
{
if (pthread_mutex_init(&lock_t, NULL) != 0)
{
perror("mutex_init err.");
return -1;
}
if(pthread_cond_init(&cond,NULL)!=0){
perror("cond_init err.");
return -1;
}
pthread_t pid1;
if (pthread_create(&pid1, NULL, handly1, NULL) != 0)
{
perror("create err.");
return -1;
}
pthread_t pid2;
if (pthread_create(&pid2, NULL, handly2, NULL) != 0)
{
perror("create err.");
return -1;
}
pthread_join(pid1, NULL);
pthread_join(pid2, NULL);
return 0;
}
上面代码是互斥锁和条件变量让原本无序打印的两个线程,按照想要的结果进行打印。