1.互斥锁:mutex,用于保证在任何时刻,都只能有一个线程访问该对象。当 获取锁擦操作失败时,线程会进入睡眠,等待锁释放时被唤醒。
在这里插入代码片
pthread_mutex_t Device_mutex ;
int count=0;
void thread_func1()
{
while(1)
{
pthread_mutex_lock(&Device_mutex);
printf("thread1: %dn",count);
pthread_mutex_unlock(&Device_mutex);
count++;
sleep(1);
}
}
void thread_func2()
{
while(1)
{
pthread_mutex_lock(&Device_mutex);
printf("thread2: %dn",count);
pthread_mutex_unlock(&Device_mutex);
count++;
sleep(1);
}
}
int main()
{
pthread_t thread1, thread2;
pthread_mutex_init(&Device_mutex,NULL);
if(pthread_create(&thread1,NULL,(void*)thread_func1,NULL) == -1)
{
printf("create IP81 Thread error !n");
exit(1);
}
if(pthread_create(&thread2,NULL,(void *)thread_func2,NULL) == -1)
{
printf("create IP81_2 Thread error!n");
exit(1);
}
sleep(1);
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
pthread_mutex_destroy(&Device_mutex);
return 0;
}
2.读写锁:rwlock,分为读锁和写锁,处于读操作时,可以允许多个线程同时获得读操作,但是同一时刻只有一个线程可以获得写锁。其他获取写锁失败的线程都会进入睡眠状态,直到写锁释放时被唤醒。注意:写锁会阻塞其他读写锁,读锁也不可以被其他线程获取。
在这里插入代码片
int counter;
pthread_rwlock_t rwlock;
void *th_write(void *arg);
void *th_read(void *arg);
int main(int argc, char *argv[])
{
int i = 0;
pthread_t tid[8];
pthread_rwlock_init(&rwlock, NULL);
//创建三个写线程
for(i = 0; i<3; i++)
{
pthread_create(&tid[i], NULL, th_write, (void*)i);//不能&i 和 i = *((int*)arg)
}
//创建5个读线程
for(i = 0; i<5; i++)
{
pthread_create(&tid[i+3], NULL, th_read, (void*)i);
}
for(i = 0; i < 8; i++)
{
pthread_join(tid[i], NULL);
}
pthread_rwlock_destroy(&rwlock);
}
void *th_write(void *arg)
{
int i = (int)arg;
int t = 0;
for( ; ; )
{
pthread_rwlock_wrlock(&rwlock);
t = counter;
usleep(1000);
printf("write %d: %lu: counter = %d ++counter = %d\n", i, pthread_self(), t, ++counter);
pthread_rwlock_unlock(&rwlock);
usleep(10000);//这个延时大的目的是让读锁有机会进行读,不然一直让写锁独占
}
return NULL;
}
void *th_read(void *arg)
{
int i = (int)arg;
for( ; ; )
{
pthread_rwlock_rdlock(&rwlock);
printf("read %d: %lu: counter = %d\n", i ,pthread_self(), counter);
pthread_rwlock_unlock(&rwlock);
usleep(2000);
}
return NULL;
}
**3.自旋锁:**spinlock,在任何时刻同样只能有一个线程访问对象,但是当获取锁操作失败时,不会进入睡眠,而是会在原地自旋,直到锁释放。这样就节省了线程从睡眠状态被唤醒期间的消耗,在加锁时间短暂等环境下会极大提升效率。
**4.RCU:**read_copy_update,在修改数据时,首先需要读取数据,然后生成一个副本,对副本进行修改。修改完成后,再将老数据update成新数据。使用RCU时,读者几乎不需要同步开销,即不需要获得锁,也不使用原子指令,不会导致锁竞争,因此不用担心死锁问题。而对于读者的同步开销较大,它需要复制被修改 的数据,还必须使用锁机制同步并行其他写者修改操作。在有大量读操作,少量写操作的情况下效率比较高。