• 同步机制之“信号量和条件变量”的应用总结


    1. 信号量与条件变量的区别

    应用场景: 信号量即可用于进程间同步,也可用于线程间同步; 条件变量只能用于线程间。

    用法上: 条件变量需要和互斥锁配合使用,而信号量之间使用就可以,所以信号量更像是条件变量和互斥锁的组合,所以必然的条件变量的使用会比信号量的使用更加灵活。毕竟,后出现的技术比之前的必然要有先进性(能解决特定的需求),才有其存在的意义。

    底层实现上:信号量内部以计数方式来判定是否阻塞(有累计数量的功能),计数单次加减1即每次只能唤醒一个进程或线程。而条件变量以“自定义条件”来判定是否阻塞(优点来了),那么它就可以唤醒一个线程或所有线程(notify_all类似广播)。

    信号量具体使用:

    1、C语言信号量接口参见 #include

    (1) 信号量的创建接口,int sem_init(sem_t *sem,int pshared,unsigned int value);

    调用成功时返回0,失败返回-1.

    参数一: 信号对象指针

    参数二: 设置它的进程间共享选项,0为不共享,其余则共享;

    参数三:设置信号量初始值,一般填0,即开始默认阻塞(当信号量值小于、等于0则阻塞)。

    (2) 信号量的等待接口,int sem_wait(sem_t *sem);  

    如果信号量的值大于0,将信号量的值减1,立即返回。如果信号量的值为0或小于0,则线程阻塞。  调用成功时返回0,失败返回-1.

    (3)信号量值加1接口,int sem_post(sem_t *sem);  

    释放信号量,让信号量的值加1。 调用成功时返回0,失败返回-1.

    (4)信号量的清理接口(相对sem_init而言),int sem_destroy(sem_t *sem);

    成功时返回0,失败时返回-1.

    示例:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. sem_t g_sem;///
    8. void func1(void* arg)
    9. {
    10. sem_wait(&sem); /线程1初始阻塞
    11. int *running=arg;
    12. printf("thread running1\n");
    13. printf("%d\n",*running);
    14. }
    15. void func2(void* arg)
    16. {
    17. printf("pthread2 running\n");
    18. sem_post(&sem); //线程2增加信号量,致使线程1阻塞被唤醒以执行后续代码
    19. }
    20. int main()
    21. {
    22. sem_init(&g_sem,0,0);信号量初始化为本进程内多线程使用,初始阻塞
    23. pthread_t thread[2];
    24. int a = 1;
    25. pthread_create(&(thread[0]),NULL,(void*)func1,(void*)&a);
    26. sleep(3);
    27. pthread_create(&(thread[1]),NULL,(void*)func2,(void*)&a);
    28. pthread_join(thread[0],NULL);
    29. pthread_join(thread[1],NULL);
    30. sem_destroy(&sem); //信号量销毁
    31. return 0;
    32. }

    2、C++  --std=c++20 信号量 counting_semaphore ,参见 #include

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. std::counting_semaphore streams_sem{0};
    7. void custom_thread(){
    8. while (1){
    9. streams_sem.acquire();
    10. std::cout << "shopping!\n";
    11. usleep(50000);
    12. }
    13. }
    14. class Prod{
    15. public:
    16. Prod(int nCnt){ m_needProCnt = nCnt; }
    17. void product() {
    18. int num = 0;
    19. while(num
    20. cout<<" product production"<
    21. streams_sem.release();
    22. ++num;
    23. }
    24. }
    25. void inner_custom(){
    26. while(1) {
    27. if ( !streams_sem.try_acquire() )
    28. {
    29. cout<<"want? no way"<
    30. break;
    31. }
    32. std::cout << "want inner shopping!\n";
    33. usleep(100000);
    34. }
    35. }
    36. private:
    37. int m_needProCnt;
    38. };
    39. int main(int argc, char const* argv[]){
    40. std::thread t1(custom_thread);
    41. t1.detach();
    42. Prod prod(20);
    43. std::thread t2(&Prod::product, &prod);
    44. std::thread t3(&Prod::inner_custom, &prod);
    45. t2.join();
    46. t3.join();
    47. return 0;
    48. }

    条件变量具体使用:

    1. template <typename T>
    2. class BlockQue {
    3. public:
    4. BlockQue():m_end(false){}
    5. ~BlockQue(){
    6. endBlockQue();
    7. }
    8. void addTask(T data){
    9. m_tasks.push(data);
    10. m_task_cv.notify_all();
    11. }
    12. void clearTask(bool del){
    13. //CAutoLock lock(m_mutexClr);
    14. while(!m_tasks.empty()){
    15. T data = std::move(m_tasks.front());
    16. m_tasks.pop();
    17. if(del){
    18. delete data;
    19. }
    20. }
    21. }
    22. bool isEmpty(){
    23. return m_tasks.empty();
    24. }
    25. int size(){
    26. return m_tasks.size();
    27. }
    28. int getTask(T& data){
    29. //CAutoLock lock(m_mutexClr);
    30. std::unique_lock lock{ m_lock };
    31. m_task_cv.wait(lock, [this]{
    32. return m_end.load() || !m_tasks.empty();//true则不阻塞
    33. });
    34. if (m_tasks.empty()){
    35. return -1;
    36. }
    37. data = std::move(m_tasks.front());
    38. m_tasks.pop();
    39. return 0;
    40. }
    41. void initBlockQue() {
    42. m_end.store(false);
    43. }
    44. void endBlockQue(){
    45. if (!m_end.load()){
    46. m_end.store(true);
    47. m_task_cv.notify_all();
    48. }
    49. }
    50. private:
    51. std::atomic<bool> m_end;
    52. std::condition_variable m_task_cv;
    53. std::queue m_tasks;
    54. std::mutex m_lock;
    55. //CMutexEx m_mutexClr;
    56. };

  • 相关阅读:
    私有git仓库只支持http情况下go mod tidy 和 go get 默认走https的问题处理 GOINSECURE
    代码随想录1刷—二叉树篇(三)
    微服务 Spring Boot 整合Redis分布式锁 Lua脚本 实现优惠卷秒杀 一人一单
    CogVLM & CogAgent模型部署
    微软开发新模型;YouTube 推出新AI功能;可折叠iPhone 或发布?
    【Java集合类面试三十】、BlockingQueue中有哪些方法,为什么这样设计?
    企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图
    2023年 python结合excel实现快速画图(零基础快速入门)
    数字时代古文的传承———云南文化瑰宝“爨文化“(我为家乡发声)
    java通过zookeeper 高可用方式连接hiveserver2
  • 原文地址:https://blog.csdn.net/fengdijiang/article/details/132871790