在多线程中,如果多线程同时在访问同一个全局变量,就会出现多个线程在获取变量值时候获取的是同一个值,此时在线程中操作这个变量就会出现不同步的效果。下面这幅图就能够演示出对应的效果。可以使用线程的互斥锁来解决这样的问题。
#include
#include
#include
#include
#define ERROR(msg) do{\
printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
printf(msg);\
exit(-1); \
}while(0)
pthread_mutex_t lock;
int money = 1000;
void* task1(void* argc)
{
while (1){
sleep(1);
pthread_mutex_lock(&lock);
if (money > 0){
money -= 50;
printf("张三取了50块钱,还剩下%d\n",money);
}else {
printf("张三取钱失败\n");
}
pthread_mutex_unlock(&lock);
}
}
void* task2(void* argc)
{
while (1){
sleep(1);
pthread_mutex_lock(&lock);
if (money > 0){
money -= 100;
printf("李四取了100块钱,还剩下%d\n",money);
}else {
printf("李四取钱失败\n");
}
pthread_mutex_unlock(&lock);
}
}
int main(int argc, char const *argv[])
{
pthread_t pid1, pid2;
pthread_mutex_init(&lock, NULL);
if (pthread_create(&pid1, NULL, task1, NULL)){
ERROR("创建失败");
}
if (pthread_create(&pid2, NULL, task2, NULL)){
ERROR("create error");
}
pthread_join(pid1, NULL);
pthread_join(pid2, NULL);
pthread_mutex_destroy(&lock);
return 0;
}
线程同步,提前已经知道线程的执行顺序,让线程顺序执行的过程就是同步。
典型的就是生产者和消费者模型。
#include
#include
#include
#include
#define ERROR(msg) do{\
printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
printf(msg);\
exit(-1); \
}while(0)
sem_t sem1, sem2;
void* task1(void* argc)
{
while(1){
sem_wait(&sem1);
printf("我生产了一辆汽车\n");
sem_post(&sem2);
}
}
void* task2(void* argc)
{
while(1){
sem_wait(&sem2);
printf("我买了一辆汽车\n");
sem_post(&sem1);
}
}
int main(int argc, char const *argv[])
{
pthread_t pid1, pid2;
sem_init(&sem1, 0, 1);
sem_init(&sem2, 0, 0);
if (pthread_create(&pid1, NULL, task1, NULL)){
ERROR("create error");
}
if (pthread_create(&pid2, NULL, task2, NULL)){
ERROR("create error");
}
pthread_join(pid1, NULL);
pthread_join(pid2, NULL);
sem_destroy(&sem1);
sem_destroy(&sem2);
return 0;
}
无名信号量适合在线程数比较少的线程中实现同步过程,而条件变量适合在大量线程
实现同步过程。例如条件变量的使用场景如下:比如你要编写一个12306买票的服务器
当客户端访问服务器的时候,服务器会创建一个线程服务于这个用户。如果有多个用户
同时想买票,此时服务需要在瞬间创建一堆线程,这个时间比较长,对用户的体验感不好。
所以12306服务是在启动的时候都已经创建好一堆线程。调用pthread_cond_wait让这些
线程休眠,当有客户端请求买票的时候,只需要唤醒这些休眠的线程即可,有于省去了
创建线程的时候,所以这种方式的效率非常的高。
#include
#include
#include
#define ERROR(msg) do{\
printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
printf(msg);\
exit(-1); \
}while(0)
pthread_cond_t cond;
pthread_mutex_t lock;
int i = 0;
void* task1(void* argc)
{
while (1){
pthread_mutex_lock(&lock);
while(i != 0){
pthread_cond_wait(&cond,&lock);
}
printf("我生产了一辆汽车\n");
i = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
void* task2(void* argc)
{
while (1){
pthread_mutex_lock(&lock);
while(i == 0){
pthread_cond_wait(&cond,&lock);
}
printf("我买了一辆汽车\n");
i = 0;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
int main(int argc, char const *argv[])
{
pthread_t pid1, pid2;
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
if (pthread_create(&pid1, NULL, task1, NULL)){
ERROR("create error");
}
if(pthread_create(&pid2, NULL, task2, NULL)){
ERROR("create error");
}
pthread_join(pid1, NULL);
pthread_join(pid2, NULL);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&lock);
return 0;
}
如果用if的话,假如是一号线程先抢到这个锁,然后生产了一辆汽车,然后唤醒了一个线程,因为此时还没有线程,然后释放锁,这个时候如果是二号进程抢到锁,那用if和while都一样,但是如果还是一号线程抢到这个锁,然后进入if i!= 0,然后由于上次唤醒的一个线程还没有用,所以此时立马唤醒,然后又生产了一辆车,这个时候就出现问题了,但是如果用while就不会,因为此时,必须得二号进程,把i == 0,这个才能往下走,不然一号进程一直在那个while循环里面。