创建两个线程,让两个线程共享一个全局变量int number,然后让每个线程数5000次数,看最后打印出这个number值是多少?
#include
#include
#include
#include
#include
#define NUM 5000
int number = 0;
void* mythread1(void *arg)
{
int i;
int n;
for(i = 0; i < NUM; ++i)
{
n = number;
n++;
number = n;
printf("1:[%d]\n", number);
}
}
void* mythread2(void* arg)
{
#include
#include
#include
#include
#include
#define NUM 5000
int number = 0;
void* mythread1(void *arg)
{
int i;
int n;
for(i = 0; i < NUM; ++i)
{
n = number;
n++;
number = n;
printf("1:[%d]\n", number);
}
}
void* mythread2(void* arg)
{
int i;
int n;
for(i = 0; i < NUM; ++i)
{
n = number;
n++;
number = n;
printf("2:[%d]\n", number);
}
}
int main()
{
pthread_t thread1;
pthread_t thread2;
int ret1 = pthread_create(&thread1, NULL, mythread1, NULL);
if(ret1 != 0)
{
printf("pthread1 create error:[%s]\n", strerror(ret1));
}
int ret2 = pthread_create(&thread2, NULL, mythread2, NULL);
if(ret2 != 0)
{
printf("pthread2 create error:[%s]\n", strerror(ret1));
}
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
分析:
n = number;
n++;
number = n;
printf("1:[%d]\n", number);
互斥锁: 线程A和线程B共同访问共享资源, 当线程A想访问共享资源的时候,要先获得锁, 如果锁被占用, 则加锁不成功需要阻塞等待对方释放锁; 若锁没有被占用, 则获得锁成功–加锁, 然后操作共享资源, 操作完之后, 必须解锁, 同理B也是和A一样.---->也就是说, 同时不能有两个线程访问共享资源, 属于互斥操作.
原子操作:该操作要么执行,要么就完成。
pthread_lock.c
#include
#include
#include
#include
#include
#include
#include
//定义一把锁
pthread_mutex_t mutex;
void *mythread1(void *args)
{
while(1)
{
//加锁
pthread_mutex_lock(&mutex);
printf("hello ");
sleep(rand()%3);
printf("world\n");
//解锁
pthread_mutex_unlock(&mutex);
sleep(rand()%3);
}
pthread_exit(NULL);
}
void *mythread2(void *args)
{
while(1)
{
//加锁
pthread_mutex_lock(&mutex);
printf("HELLO ");
sleep(rand()%3);
printf("WORLD\n");
//解锁
pthread_mutex_unlock(&mutex);
sleep(rand()%3);
}
pthread_exit(NULL);
}
int main()
{
int ret;
pthread_t thread1;
pthread_t thread2;
//随机数种子
srand(time(NULL));
//互斥锁初始化
pthread_mutex_init(&mutex, NULL);
ret = pthread_create(&thread1, NULL, mythread1, NULL);
if(ret!=0)
{
printf("pthread_create error, [%s]\n", strerror(ret));
return -1;
}
ret = pthread_create(&thread2, NULL, mythread2, NULL);
if(ret!=0)
{
printf("pthread_create error, [%s]\n", strerror(ret));
return -1;
}
//等待线程结束
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
//释放互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}
自己锁自己.
注意点: 线程在异常退出的时候也需要解锁.
A线程占用着A锁, 又想去获得B锁; B线程占用着B锁, 又想去获得A锁,
两个线程都不释放自己的锁, 又想去获得对方的锁, 从而造成了死锁.
解决方法:
1 需要先释放自己的锁再去获得其他锁
2 避免使用嵌套的锁, 让线程按照一定的顺序加锁
3 可以调用pthread_mutex_trylock函数加锁, 该函数不阻塞, 所以不会产生死锁.
读写锁场景:
1.线程A加写锁成功, 线程B请求读锁
线程B阻塞,
当线程A解锁之后, 线程B加锁成功
2.线程A持有读锁, 线程B请求写锁
线程B会阻塞;
当线程A解锁之后, 线程B加锁成功
3.线程A拥有读锁, 线程B请求读锁
线程B请求锁成功
4.线程A持有读锁, 然后线程B请求写锁, 然后线程C请求读锁
线程B和C都阻塞;
当A释放锁之后, B先获得锁, C阻塞
当B释放锁之后, C获得锁
5.线程A持有写锁, 然后线程B请求读锁, 然后线程C请求写锁
线程B和C都阻塞;
当线程A解锁之后, C先获得锁, B阻塞;
当C解锁之后, B获得锁
读写锁总结
写独占, 读共享, 当读和写一起等待锁的时候, 写的优先级高
pthread_rwlock.c
//读写锁测试程序
#include
#include
#include
#include
#include
#include
int number = 0;
//定义一把读写锁
pthread_rwlock_t rwlock;
//写线程回调函数
void *thread_write(void *arg)
{
int i = *(int *)arg;
int cur;
while(1)
{
//加写锁
pthread_rwlock_wrlock(&rwlock);
cur = number;
cur++;
number = cur;
printf("[%d]-W:[%d]\n", i, cur);
//解锁
pthread_rwlock_unlock(&rwlock);
sleep(rand()%3);
}
}
//读线程回调函数
void *thread_read(void *arg)
{
int i = *(int *)arg;
int cur;
while(1)
{
//加读锁
pthread_rwlock_rdlock(&rwlock);
cur = number;
printf("[%d]-R:[%d]\n", i, cur);
//解锁
pthread_rwlock_unlock(&rwlock);
sleep(rand()%3);
}
}
int main()
{
int n = 8;
int i = 0;
int arr[8];
pthread_t thread[8];
//读写锁初始化
pthread_rwlock_init(&rwlock, NULL);
//创建3个写子线程
for(i=0; i<3; i++)
{
arr[i] = i;
pthread_create(&thread[i], NULL, thread_write, &arr[i]);
}
//创建5个读子线程
for(i=3; i<n; i++)
{
arr[i] = i;
pthread_create(&thread[i], NULL, thread_read, &arr[i]);
}
//回收子线程
int j = 0;
for(j=0;j<n; j++)
{
pthread_join(thread[j], NULL);
}
//释放锁
pthread_rwlock_destroy(&rwlock);
return 0;
}
//使用条件变量实现生产者和消费者模型
#include
#include
#include
#include
#include
#include
typedef struct node
{
int data;
struct node *next;
}NODE;
NODE *head = NULL;
//定义一把锁
pthread_mutex_t mutex;
//定义条件变量
pthread_cond_t cond;
//生产者线程
void *producer(void *arg)
{
NODE *pNode = NULL;
while(1)
{
//生产一个节点
pNode = (NODE *)malloc(sizeof(NODE));
if(pNode==NULL)
{
perror("malloc error");
exit(-1);
}
pNode->data = rand()%1000;
printf("P:[%d]\n", pNode->data);
//加锁
pthread_mutex_lock(&mutex);
pNode->next = head;
head = pNode;
//解锁
pthread_mutex_unlock(&mutex);
//通知消费者线程解除阻塞
pthread_cond_signal(&cond);
sleep(rand()%3);
}
}
//消费者线程
void *consumer(void *arg)
{
NODE *pNode = NULL;
while(1)
{
//加锁
pthread_mutex_lock(&mutex);
if(head==NULL)
{
//若条件不满足,需要阻塞等待
//若条件不满足,则阻塞等待并解锁;
//若条件满足(被生成者线程调用pthread_cond_signal函数通知),解除阻塞并加锁
pthread_cond_wait(&cond, &mutex);
}
printf("C:[%d]\n", head->data);
pNode = head;
head = head->next;
//解锁
pthread_mutex_unlock(&mutex);
free(pNode);
pNode = NULL;
sleep(rand()%3);
}
}
int main()
{
int ret;
pthread_t thread1;
pthread_t thread2;
//初始化互斥锁
pthread_mutex_init(&mutex, NULL);
//条件变量初始化
pthread_cond_init(&cond, NULL);
//创建生产者线程
ret = pthread_create(&thread1, NULL, producer, NULL);
if(ret!=0)
{
printf("pthread_create error, [%s]\n", strerror(ret));
return -1;
}
//创建消费者线程
ret = pthread_create(&thread2, NULL, consumer, NULL);
if(ret!=0)
{
printf("pthread_create error, [%s]\n", strerror(ret));
return -1;
}
//等待线程结束
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
//释放互斥锁
pthread_mutex_destroy(&mutex);
//释放条件变量
pthread_cond_destroy(&cond);
return 0;
}
假若只有一个生产者生产了一个节点, 此时会调用pthread_cond_signal通知消费者线程, 此时若有多个消费者被唤醒了, 则最终只有消费者获得锁, 然后进行消费, 此时会将head置为NULL, 然后其余的几个消费者线程只会有一个线程获得锁, 然后读取head的内容就会core掉.
pthread_cond_mul.c
//使用条件变量实现生产者和消费者模型
#include
#include
#include
#include
#include
#include
typedef struct node
{
int data;
struct node *next;
}NODE;
NODE *head = NULL;
//定义一把锁
pthread_mutex_t mutex;
//定义条件变量
pthread_cond_t cond;
//生产者线程
void *producer(void *arg)
{
NODE *pNode = NULL;
int n = *(int *)arg;
while(1)
{
//生产一个节点
pNode = (NODE *)malloc(sizeof(NODE));
if(pNode==NULL)
{
perror("malloc error");
exit(-1);
}
pNode->data = rand()%1000;
printf("P[%d]:[%d]\n", n, pNode->data);
//加锁
pthread_mutex_lock(&mutex);
pNode->next = head;
head = pNode;
//解锁
pthread_mutex_unlock(&mutex);
//通知消费者线程解除阻塞
pthread_cond_signal(&cond);
sleep(rand()%3);
}
}
//消费者线程
void *consumer(void *arg)
{
NODE *pNode = NULL;
int n = *(int *)arg;
while(1)
{
//加锁
pthread_mutex_lock(&mutex);
if(head==NULL)
{
//若条件不满足,需要阻塞等待
//若条件不满足,则阻塞等待并解锁;
//若条件满足(被生成者线程调用pthread_cond_signal函数通知),解除阻塞并加锁
pthread_cond_wait(&cond, &mutex);
}
if(head==NULL)
{
//解锁
pthread_mutex_unlock(&mutex);
continue;
}
printf("C[%d]:[%d]\n", n, head->data);
pNode = head;
head = head->next;
//解锁
pthread_mutex_unlock(&mutex);
free(pNode);
pNode = NULL;
sleep(rand()%3);
}
}
int main()
{
int ret;
int i = 0;
pthread_t thread1[5];
pthread_t thread2[5];
//初始化互斥锁
pthread_mutex_init(&mutex, NULL);
//条件变量初始化
pthread_cond_init(&cond, NULL);
int arr[5];
for(i=0; i<5; i++)
{
arr[i]= i;
//创建生产者线程
ret = pthread_create(&thread1[i], NULL, producer, &arr[i]);
if(ret!=0)
{
printf("pthread_create error, [%s]\n", strerror(ret));
return -1;
}
//创建消费者线程
ret = pthread_create(&thread2[i], NULL, consumer, &arr[i]);
if(ret!=0)
{
printf("pthread_create error, [%s]\n", strerror(ret));
return -1;
}
}
//等待线程结束
for(i=0; i<5; i++)
{
pthread_join(thread1[i], NULL);
pthread_join(thread2[i], NULL);
}
//释放互斥锁
pthread_mutex_destroy(&mutex);
//释放条件变量
pthread_cond_destroy(&cond);
return 0;
}
在使用条件变量的线程中, 能够引起线程的阻塞的地方有两个:
定义信号量变量
sem_t sem1;
sem_t sem2;
初始化信号量
sem_init(&sem1, 0, 5);
sem_init(&sem2, 0, 5);
加锁
sem_wait(&sem1);
//共享资源
sem_post(&sem2);
sem_wait(&sem2);
//共享资源
sem_post(&sem1);
释放资源
sem_destroy(sem1);
sem_destroy(sem2);
pthread_sem.c
//使用信号量实现生产者和消费者模型
#include
#include
#include
#include
#include
#include
#include
typedef struct node
{
int data;
struct node *next;
}NODE;
NODE *head = NULL;
//定义信号量
sem_t sem_producer;
sem_t sem_consumer;
//生产者线程
void *producer(void *arg)
{
NODE *pNode = NULL;
while(1)
{
//生产一个节点
pNode = (NODE *)malloc(sizeof(NODE));
if(pNode==NULL)
{
perror("malloc error");
exit(-1);
}
pNode->data = rand()%1000;
printf("P:[%d]\n", pNode->data);
//加锁
sem_wait(&sem_producer); //--
pNode->next = head;
head = pNode;
//解锁
sem_post(&sem_consumer); //相当于++
sleep(rand()%3);
}
}
//消费者线程
void *consumer(void *arg)
{
NODE *pNode = NULL;
while(1)
{
//加锁
sem_wait(&sem_consumer); //相当于--
printf("C:[%d]\n", head->data);
pNode = head;
head = head->next;
//解锁
sem_post(&sem_producer); //相当于++
free(pNode);
pNode = NULL;
sleep(rand()%3);
}
}
int main()
{
int ret;
pthread_t thread1;
pthread_t thread2;
//初始化信号量
sem_init(&sem_producer, 0, 5);
sem_init(&sem_consumer, 0, 0);
//创建生产者线程
ret = pthread_create(&thread1, NULL, producer, NULL);
if(ret!=0)
{
printf("pthread_create error, [%s]\n", strerror(ret));
return -1;
}
//创建消费者线程
ret = pthread_create(&thread2, NULL, consumer, NULL);
if(ret!=0)
{
printf("pthread_create error, [%s]\n", strerror(ret));
return -1;
}
//等待线程结束
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
//释放信号量资源
sem_destroy(&sem_producer);
sem_destroy(&sem_consumer);
return 0;
}