多个线程临界资源争抢写入操作会造成逻辑混乱/数据丢失二义性,因此就引入线程安全概念。
线程使用本身就是线程间通信方便成本低而广为使用。这样的话就无法避免资源争抢操作,这时候就必须考虑线程安全。
保证线程安全更多指的是保证数据的安全访问,保证数据访问的原子性不会被打断(互斥/同步)
线程间如何实现互斥与同步:
互斥:互斥锁---保证数据的同一时间唯一访问
同步:条件变量---让数据的访问更具有时间的可控性
/* 这是一个黄牛抢票的demo,互斥锁的使用
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
volatile ticket = 100;
pthread_mutex_t mutex;
void *yellow_cow(void *arg)
{
int id = (int)arg;
while(1) {
//int pthread_mutex_lock(pthread_mutex_t *mutex);
//int pthread_mutex_trylock(pthread_mutex_t *mutex);
//int pthread_mutex_unlock(pthread_mutex_t *mutex);
//lock 阻塞加锁,trylock 非阻塞加锁,timedlock 限时阻塞加锁
pthread_mutex_lock(&mutex);
if (ticket > 0) {
usleep(100);
ticket--;
printf("cow %d get ticket:%d\n", id, ticket);
}else {
//在任何有可能退出的地方都必须在退出前解锁
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main()
{
int max = 4, i;
pthread_t tid[4];
// 互斥锁变量的初始化
//int pthread_mutex_init(pthread_mutex_t *restrict mutex,
// const pthread_mutexattr_t *restrict attr);
// 这种初始化,在使用结束后必须要释放
// mutex: 互斥锁变量
// attr: 属性,通常置NULL
//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init(&mutex, NULL);
for (i = 0; i < max; i++) {
int ret = pthread_create(&tid[i],NULL,yellow_cow,(void*)i);
if (ret != 0) {
printf("create thread error\n");
return -1;
}
}
for (i = 0; i < max; i++) {
pthread_join(tid[i], NULL);
}
//int pthread_mutex_destroy(pthread_mutex_t *mutex);
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}