C++ mutex常见问题
1.Linux
1.2普通锁、递归锁、错误检查锁
当线程1已经加锁
线程1再次加锁 | 线程2加锁 | |
---|---|---|
普通锁 | 死锁 | 线程2挂起(suspend) |
错误检查锁 | 返回错误码EDEADLK线程不挂起 | 返回错误码EDEADLK,现场不挂起 |
递归锁 | Y | 线程2挂起(suspend) |
错误检查锁实例1::线程1已经加锁,尝试再次加锁
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
int main() {
pthread_mutexattr_t attr;
pthread_mutex_t mutex;
// 初始化互斥锁属性
pthread_mutexattr_init(&attr);
// 设置为错误检查锁
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
// 使用错误检查属性初始化互斥锁
pthread_mutex_init(&mutex, &attr);
// 销毁互斥锁属性对象
pthread_mutexattr_destroy(&attr);
// 线程 1 第一次加锁
if (pthread_mutex_lock(&mutex) != 0) {
perror("First lock failed");
return 1;
}
// 线程 1 再次加锁
int ret = pthread_mutex_lock(&mutex);
if (ret == EDEADLK) {
printf("Deadlock detected when trying to lock again (error code: EDEADLK)\n");
} else if (ret != 0) {
perror("Second lock failed");
}
// 释放锁
pthread_mutex_unlock(&mutex);
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}
输出结果为
Deadlock detected when trying to lock again (error code: EDEADLK)
错误检查锁实例2::线程1已经加锁(未释放),线程2进行加锁.
注:这个实例似乎运行有问题,线程1执行完已经反馈,但是线程2一直阻塞在加锁的地方。难道这是因为我用虚拟机的原因吗?留个小疑问。
#include <iostream>
#include <pthread.h>
#include <errno.h>
// 定义互斥锁和互斥锁属性
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
// 线程 1 函数
void* thread1Function(void* arg) {
// 线程 1 加锁
int result = pthread_mutex_lock(&mutex);
if (result != 0) {
std::cerr << "Thread 1: Lock failed with error code: " << result << std::endl;
} else {
std::cout << "Thread 1: Lock acquired." << std::endl;
// 模拟线程 1 持有锁一段时间
sleep(2);
}
std::cout << "Thread 1: return." << std::endl;
return NULL;
}
// 线程 2 函数
void* thread2Function(void* arg) {
// 线程 2 等待一段时间,确保线程 1 先加锁
sleep(1);
// 线程 2 尝试加锁
std::cout << "Thread 2: want to lock." << std::endl;
int result = pthread_mutex_lock(&mutex);
std::cout << "Thread 2: excute lock end." << std::endl;
if (result == 0) {
std::cout << "Thread 2: Lock acquired." << std::endl;
// 线程 2 释放锁
pthread_mutex_unlock(&mutex);
} else if (result == EBUSY) {
std::cout << "Thread 2: Lock is already held by another thread." << std::endl;
} else {
std::cerr << "Thread 2: Lock failed with error code: " << result << std::endl;
}
return NULL;
}
int main() {
// 初始化互斥锁属性
if (pthread_mutexattr_init(&attr) != 0) {
std::cerr << "Failed to initialize mutex attributes." << std::endl;
return 1;
}
// 设置互斥锁属性为错误检查锁
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
{
std::cerr << "Failed to set mutex attribute type." << std::endl;
return 1;
}
// 使用设置好的属性初始化互斥锁
if (pthread_mutex_init(&mutex, &attr) != 0) {
std::cerr << "Failed to initialize mutex." << std::endl;
return 1;
}
pthread_mutexattr_destroy(&attr);
// 创建线程 1 和线程 2
pthread_t thread1, thread2;
if (pthread_create(&thread1, NULL, thread1Function, NULL) != 0) {
std::cerr << "Failed to create thread 1." << std::endl;
return 1;
}
else
{
std::cout << "Thread 1: join successful." << std::endl;
}
if (pthread_create(&thread2, NULL, thread2Function, NULL) != 0) {
std::cerr << "Failed to create thread 2." << std::endl;
return 1;
}
else
{
std::cout << "Thread 2: join successful." << std::endl;
}
// 等待线程 1 和线程 2 结束
if (pthread_join(thread1, NULL) != 0) {
std::cerr << "Failed to join thread 1." << std::endl;
return 1;
}
if (pthread_join(thread2, NULL) != 0) {
std::cerr << "Failed to join thread 2." << std::endl;
return 1;
}
sleep(8);
// 销毁互斥锁和互斥锁属性
if (pthread_mutex_destroy(&mutex) != 0) {
std::cerr << "Failed to destroy mutex." << std::endl;
return 1;
}
//pthread_mutexattr_destroy(&attr);
return 0;
}
2.pthread_mutex_lock与pthread_mutex_trylock作用/应用
pthread_mutex_lock
作用:
pthread_mutex_lock 函数用于锁定一个互斥锁。如果互斥锁已经被其他线程锁定,调用此函数的线程将被阻塞,直到互斥锁变为可用并被当前线程获取为止。
应用场景:
当需要确保在访问共享资源时没有其他线程能够同时访问该资源时,应使用 pthread_mutex_lock。
在临界区代码之前调用 pthread_mutex_lock,以确保在进入临界区之前获取到锁。
适用于那些可以等待锁变为可用的场景,因为调用线程在锁不可用时会进入阻塞状态。
pthread_mutex_trylock
作用:
pthread_mutex_trylock 函数尝试获取一个互斥锁,但如果互斥锁已经被其他线程锁定,则不会阻塞当前线程,而是立即返回一个值来表示是否成功获取到锁。
应用场景:
当需要尝试获取锁但不想阻塞当前线程时,应使用 pthread_mutex_trylock。
在非临界区代码中,或者当线程有其他任务可以执行而不想等待锁时,可以使用 pthread_mutex_trylock。
适用于那些需要立即知道是否能够获取锁的场景,以便根据结果做出不同的处理。
返回值:
如果成功获取到锁,pthread_mutex_trylock 返回 0。
如果锁已经被其他线程获取,则返回非零值(通常是 EBUSY 或 EAGAIN),表示无法立即获取锁。
比较与应用选择
阻塞与非阻塞:pthread_mutex_lock 是阻塞的,而 pthread_mutex_trylock 是非阻塞的。
适用场景:根据程序的需求选择使用哪个函数。如果需要确保获取到锁才继续执行,则使用 pthread_mutex_lock;如果希望尝试获取锁但不想等待,则使用 pthread_mutex_trylock。
错误处理:在使用 pthread_mutex_trylock 时,需要手动检查返回值,并根据结果做出相应的处理(如重试、执行其他任务或退出等)。
综上所述,pthread_mutex_lock 和 pthread_mutex_trylock 在多线程编程中各有其适用的场景和作用。选择哪个函数取决于程序的具体需求和线程的行为模式。