1.
自旋锁
自旋锁也是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。
无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。
但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者进入睡眠状态。但是自旋锁不会引起申请者睡眠,如果自旋锁已经被占用,调用者就一直循环在那里判断占用者是否已经释放了锁,“自旋”一词就是因此而得名(空转锁)。
自旋锁主要用于Linux内核同步。
相关函数
1)初始化锁。
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
2)阻塞加锁,若互斥锁已经被其它线程上锁,则调用者一直阻塞等待,直到被解锁后才上锁。
int pthread_spin_lock(pthread_spinlock_t *lock);
3)非阻塞加锁,若互斥锁未加锁,则上锁,若互斥锁已加锁,则函数立即返回失败.
int pthread_spin_trylock(pthread_spinlock_t*lock);
4)解锁。
int pthread_spin_unlock(pthread_spinlock_t*lock);
5)销毁锁,释放资源。
int pthread _spin_destroy(pthread_spinlock_t *lock);
自旋锁也存在优先唤醒的问题。
//b 自选
#include <unistd.h>
#include <pthread.h>
#include <string.h>
char buffer[101]; //全局共享的buffer.
pthread_spinlock_t spin; //声明自旋锁
void *pthfun(void *arg)
{
for (int ii = 0; ii < 3; ii++)
{
printf("%d:%ld:lock...\n",time(0),(long)arg);
pthread_spin_lock(&spin);
printf("%d:%ld:lock ok. \n",time(0),(long)arg);
//操作共享的全局变量。
sprintf(buffer,"%d:%ld,%d",time(0),pthread_self(),ii);
sleep(5);
pthread_spin_unlock(&spin);
printf("%d:%ld:unlock... \n",time(0),(long)arg);
usleep(100);
}
}
int main()
{
pthread_spin_init(&spin,PTHREAD_PROCESS_PRIVATE); //初始化锁。
pthread_t pthid1,pthid2;
pthread_create(&pthid1,NULL,pthfun,(void *)1);
pthread_create(&pthid2,NULL,pthfun,(void *)2);
pthread_join(pthid1,NULL);
pthread_join(pthid2,NULL);
pthread_spin_destroy(&spin); //销毁锁。
return 0;
}
这段代码使用自旋锁保护了全局共享的缓冲区 `buffer`,并在两个线程中进行了并发访问。
每个线程的执行流程如下:
1. 线程获取自旋锁,进入临界区。
2. 线程操作全局共享的缓冲区 `buffer`。
3. 线程释放自旋锁,退出临界区。这个程序使用 `pthread_spin_lock()` 和 `pthread_spin_unlock()` 函数来获取和释放自旋锁。在两个线程中并行执行时,它们会交替获取和释放自旋锁来保护全局共享的缓冲区。注意到 `buffer` 数组是全局共享的,如果不使用自旋锁来进行保护,会产生竞争条件导致多个线程同时访问和修改该缓冲区,导致不可预知的结果。
当线程运行时, `sprintf()` 函数会把当前时间戳、线程 ID 和循环计数器的值格式化到 `buffer` 缓冲区,在紧接着的 5 秒钟内通过 `sleep()` 函数模拟线程执行其他的任务。由于 `buffer` 缓冲区是全局共享的,它的内容可能会被其他线程读取和修改,因此需要使用自旋锁进行保护。
值得注意的是,这个程序在销毁自旋锁之前调用了 `pthread_join()` 函数来等待两个线程的执行完成,这是因为如果在等待线程执行完成之前销毁锁,会导致未定义的行为。
需要指出的是,自旋锁通常是在共享资源访问竞争不激烈的情况下使用,而且实现的正确性也需要根据实际情况进行评估和测试。
结果:
1702177416:2:lock...
1702177416:2:lock ok.
1702177416:1:lock...
1702177421:1:lock ok.
1702177421:2:unlock...
1702177421:2:lock...
1702177426:1:unlock...
1702177426:2:lock ok.
1702177426:1:lock...
1702177431:2:unlock...
1702177431:1:lock ok.
1702177431:2:lock...
1702177436:1:unlock...
1702177436:2:lock ok.
1702177436:1:lock...
1702177441:2:unlock...
1702177441:1:lock ok.
1702177446:1:unlock...
理解 : 就是
两边交替 打印
一个 如果对方 已经拿到锁, 就等待
等对方 释放 , 我们 这边 就 可以拿到锁 了;