Linux应用开发 - 线程同步的三种方法
创始人
2024-02-16 00:17:54
0

Linux应用开发 - 线程同步

线程同步的三种方法

  • 互斥锁(Mutex)
  • 条件变量(cond)
  • 信号量(sem)

互斥锁(Mutex)

存在的意义:用来同步同一个进程中的各个线程。如果这个互斥量存放在多个进程共享的某个内存中,则还能通过互斥量来进行进程间同步。

互斥量是一种特殊的二值信号量,类似于当只有一个车位的停车场,当一辆车进入的时候,将停车场大门锁上,如果再有车辆想进来的话就必须等到里面那辆车出来,才能进去。

声明的数据类型为:pthread_mutex_t中有具体定义。

pthread_mutex_t myMutex;

  • 互斥锁的初始化

    // ①使用特定的宏
    pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;
    // ②调用初始化函数
    pthread_mutex_t myMutex;
    pthread_mutex_init(&myMutex , NULL);
    
    • pthread_mutex_init()函数可以自定义互斥锁的属性

      int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
      
      • mutex:表示要初始化的互斥锁
      • attr:自定义新建互斥锁的属性,为NULL时表示以默认属性创建互斥锁
      • 返回值:成功:0;失败:非零数
  • 互斥锁的 “加锁” 和 “解锁”

    • int pthread_mutex_lock(pthread_mutex_t* mutex);   //实现加锁
      int pthread_mutex_trylock(pthread_mutex_t* mutex);  //实现加锁
      int pthread_mutex_unlock(pthread_mutex_t* mutex);   //实现解锁
      
    • pthread_mutex_unlock()函数用于对指定互斥锁进行“解锁操作”

    • pthread_mutex_lock() 和 pthread_mutex_trylock() 函数都用于实现“加锁”操作,不同之处在于当互斥锁已经处于“加锁”状态时 执行 pthread_mutex_lock() 函数会使线程进入等待(阻塞)状态,直至互斥锁得到释放;执行 pthread_mutex_trylock() 函数不会阻塞线程,直接返回非零数(表示加锁失败)。

  • 互斥锁的销毁

    • int pthread_mutex_destroy(pthread_mutex_t *mutex);
      
      • mutex:要销毁的互斥锁
      • 返回值:成功:0;失败:非零数

      注意,对于用 PTHREAD_MUTEX_INITIALIZER 或者 pthread_mutex_init() 函数直接初始化的互斥锁,无需调用 pthread_mutex_destory() 函数手动销毁。

案例

/**多线程临界资源访问* 多个线程操作公共资源,如果是全局变量,会出现“矛盾”的现象* 例如:线程1想要变量自增,线程2想要变量自减* 通过互斥量管理共享资源*/
#define _GNU_SOURCE
#include 
#include 
#include 
#include pthread_mutex_t mutex;int num = 0;void *func()
{pthread_mutex_lock(&mutex);while (num < 3){num++;printf("%s num = %d\n", __FUNCTION__, num);sleep(1);/* code */}pthread_mutex_unlock(&mutex);pthread_exit(NULL);
}
void *func1()
{pthread_mutex_lock(&mutex);while (num > -3){num--;printf("%s num = %d\n", __FUNCTION__, num);sleep(1);/* code */}pthread_mutex_unlock(&mutex);pthread_exit(NULL);
}int main()
{pthread_t tid1, tid2;int rmutex = pthread_mutex_init(&mutex,NULL);if (rmutex != 0){perror("init mutex fail\n");return -1;/* code */}int ret = pthread_create(&tid1, NULL, func, NULL);if (ret != 0){perror("creat thread fail\n");return -1;/* code */}ret = pthread_create(&tid2, NULL, func1, NULL);if (ret != 0){perror("creat thread fail\n");return -1;/* code */}pthread_join(tid1, NULL);pthread_join(tid2, NULL);return 0;
}

运行结果:

func num = 1
func num = 2
func num = 3
func1 num = 2
func1 num = 1
func1 num = 0
func1 num = -1
func1 num = -2
func1 num = -3

条件变量(cond)

mutex体现的是一种竞争,我离开了,通知你进来。

cond体现的是一种协作,我准备好了,通知你开始吧。

条件变量是另一种线程同步机制,主要是用来等某个条件发生。可以用来同步同一进程中的各个线程。跟互斥量一样如果存放在多个进程共享的某个内存中时,可以通过条件来进行进程间的同步。

每个条件变量总是和一个互斥量关联,条件本身是由互斥量保护的,线程在改变条件状态之间必须要锁住互斥量。

条件变量相对于互斥量最大的优点是允许线程以无竞争的方式灯等待条件的发生。当某个线程获取到互斥锁之后,发现需要等待某个条件变量为真,如果是这样,该线程就可以等待在某个条件上,不需要通过轮训的方式占用CPU

案例

/**条件变量和互斥量*/
#define _GNU_SOURCE
#include 
#include 
#include 
#include #define     BUFFER_SIZE     5   //产品库存大小
#define     PRODUCT_CNT     6  //产品生产总数struct product_cons
{int buffer[BUFFER_SIZE];pthread_mutex_t lock;   //互斥锁int readpos,writepos;pthread_cond_t  notempty;   //条件变量非空pthread_cond_t  notfull;    //条件变量非满/* data */
}buffer;void init(struct product_cons *p)
{pthread_mutex_init(&p->lock,NULL);pthread_cond_init(&p->notempty,NULL);pthread_cond_init(&p->notfull,NULL);p->readpos = 0;p->writepos = 0;
}void finish(struct product_cons *p)
{pthread_mutex_destroy(&p->lock);pthread_cond_destroy(&p->notempty);pthread_cond_destroy(&p->notfull);p->readpos = 0;p->writepos = 0;
}void put(struct product_cons *p,int data)
{pthread_mutex_lock(&p->lock);if((p->writepos+1)%BUFFER_SIZE == p->readpos)//检查仓库非满状态才能生产{printf("curr full\n");pthread_cond_wait(&p->notfull,&p->lock);}p->buffer[p->writepos] = data;p->writepos++;if(p->writepos >= BUFFER_SIZE)p->writepos = 0;pthread_cond_signal(&p->notempty);pthread_mutex_unlock(&p->lock);
}int get(struct product_cons *p)
{int data;pthread_mutex_lock(&p->lock);if(p->readpos == p->writepos){printf("consumer wait not empty\n");pthread_cond_wait(&p->notempty,&p->lock);}data = p->buffer[p->readpos];p->readpos++;if(p->readpos>=BUFFER_SIZE)p->readpos = 0;pthread_cond_signal(&p->notfull);pthread_mutex_unlock(&p->lock);return data;
}void *producer(void *data) //子线程,生产
{for (int i = 0; i < 50; i++)    //生产50个产品{sleep(1);printf("put the %d product..\n",i);put(&buffer,i);// printf("put the %d product success\n",i);/* code */}printf("producer stopped\n");return NULL;
}void *consumer(void *data) //子线程,消费
{static int cnt = 0;int num;while (1){sleep(2);// printf("get product...\n");num = get(&buffer);printf("get the %d product success\n",num);if(++cnt == PRODUCT_CNT)break;/* code */}printf("consumer stopped\n");return  NULL;
}int main()
{pthread_t tid1, tid2;init(&buffer);int ret = pthread_create(&tid1, NULL, producer, NULL);if (ret != 0){perror("creat thread fail\n");return -1;/* code */}ret = pthread_create(&tid2, NULL, consumer, NULL);if (ret != 0){perror("creat thread fail\n");return -1;/* code */}pthread_join(tid1, NULL);pthread_join(tid2, NULL);finish(&buffer);return 0;
}

运行结果:

put the 0 product..
get the 0 product success
put the 1 product..
put the 2 product..
get the 1 product success
put the 3 product..
put the 4 product..
get the 2 product success
put the 5 product..
put the 6 product..
get the 3 product success
put the 7 product..
put the 8 product..
curr full
get the 4 product success
put the 9 product..
curr full
get the 5 product success
consumer stopped
put the 10 product..
curr full

这个例程主要就是解决生产者和消费者冲突的问题,互斥量的话也能实现,只不过生产完了再消费。加个条件变量的话,边生产边消费。

信号量(sem)

如同进程一样,线程也可以通过信号量来实现通信,虽然是轻量级的。信号量函数的名字都以"sem_"打头。线程使用的基本信号量函数有四个。

  • 信号量初始化

    int sem_init (sem_t *sem , int pshared, unsigned int value);

    • 这是对由sem指定的信号量进行初始化,设置好它的共享选项(linux 只支持为0,即表示它是当前进程的局部信号量),然后给它一个初始值VALUE

    int sem_wait(sem_t *sem);

    • 等待信号量。给信号量减1,然后等待直到信号量的值大于0。

    int sem_post(sem_t *sem);

    • 释放信号量。信号量值加1。并通知其他等待线程。

    int sem_destroy(sem_t *sem);

    • 销毁信号量。我们用完信号量后都它进行清理。归还占有的一切资源。

案例

/**线程信号量控制测试**/
#define _GNU_SOURCE
#include 
#include 
#include 
#include 
#include sem_t sem_1, sem_2, sem_3;void *func1()
{sem_wait(&sem_1);printf("%s,come!\n", __FUNCTION__);sem_post(&sem_2);pthread_exit(NULL);
}
void *func2()
{sem_wait(&sem_2);printf("%s,come!\n", __FUNCTION__);sem_post(&sem_3);pthread_exit(NULL);
}
void *func3()
{sem_wait(&sem_3);printf("%s,come!\n", __FUNCTION__);sem_post(&sem_1);pthread_exit(NULL);
}int main()
{pthread_t tid1, tid2, tid3;/*int sem_init(sem_t *sem,int pshared,unsigned int value);参数1:sem_t类型地址参数2:0表示线程控制,否则为进程控制参数3:信号量的初始值0:阻塞1:运行*/int rsem = sem_init(&sem_1, 0, 1);if (rsem < 0){perror("sem_init fail\n");return -1;/* code */}rsem = sem_init(&sem_2, 0, 0);if (rsem < 0){perror("sem_init fail\n");return -1;/* code */}rsem = sem_init(&sem_3, 0, 0);if (rsem < 0){perror("sem_init fail\n");return -1;/* code */}int ret = pthread_create(&tid1, NULL, func1, NULL);if (ret != 0){perror("creat thread fail\n");return -1;/* code */}ret = pthread_create(&tid2, NULL, func2, NULL);if (ret != 0){perror("creat thread fail\n");return -1;/* code */}ret = pthread_create(&tid3, NULL, func3, NULL);if (ret != 0){perror("creat thread fail\n");return -1;/* code */}/*回收线程资源*/pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);/*销毁信号量*/sem_destroy(&sem_1);sem_destroy(&sem_2);sem_destroy(&sem_3);return 0;
}

运行效果:

func1,come!
func2,come!
func3,come!

在这个案例中,只初始化sem_1值为1,sem_2 sem_3初始化都为0,线程1中sem_post给信号量2控制块,这样线程2就能运行。

相关内容

热门资讯

因违反医疗法规,淄博高新区四季... 近日,淄博高新技术产业开发区管理委员会发布一则行政处罚决定书,淄博高新区四季青医院有限公司因违反《医...
宋城演艺:境外投资者通过合规渠... 证券之星消息,宋城演艺(300144)12月22日在投资者关系平台上答复投资者关心的问题。 投资者提...
漯河:公积金政策已做调整! 12月23日,漯河市住房公积金管理中心发布《关于住房公积金缴存基数调整工作的提醒》。我市住房公积金缴...
陕国投A:增发定价符合法规及国... 证券之星消息,陕国投A(000563)12月22日在投资者关系平台上答复投资者关心的问题。 投资者提...
公共利益保护实录:7个行政公益... 从农用地保护到抗战文物抢救,从处方药安全到妇女平等就业——行政公益诉讼如何以司法之力守护公共利益?2...
百亿富豪涉嫌犯罪!上海知名乐园... 12月22日晚,海昌海洋公园发布公告称,海昌海洋公园收到公司董事会主席、执行董事兼行政总裁俞发祥家属...
格陵兰岛总理:格陵兰岛领土完整... 当地时间12月23日,格陵兰岛自治政府总理尼尔森再次重申,格陵兰岛的领土完整和法律地位根植于国际法,...
被起诉的AI独角兽,这样回应好... AIX财经(AIXcaijing)原创 作者 | 陈丹 编辑 | 魏佳 AI与版权的战争,或许正迎来...
桃源法院:车祸背后的温情调解 ... “法官,我知道是我撞了人,可我刚毕业实在没能力赔这么多……”在桃源县人民法院的审判庭内,外卖员琚某的...
江西上高:高效调解有温度 倾力... 近年来,江西省宜春市上高县市场监督管理局始终以“维护消费合法权益,共筑满意消费环境”为目标,持续完善...