C++中的多线程

c++线程中的几种锁

  • 在代码中使用pthread,进行编译时,需要使用命令 g++ -o hello hello.c -lpthread
  • Makefile怎么写?

互斥锁

互斥锁只有两种状态,锁定非锁定

头文件:<pthread.h>
类型:pthread_mutex_t

  • pthread_mutex_lock:加锁。如果锁已经被占有,则该线程加入一个队列中。
  • pthread_mutex_trylock:尝试加锁,如果锁已被占有,则线程不加入队列,而是返回错误。
  • pthread_mutex_unlock:释放锁

Linux c++ 多线程编程基础——互斥锁

例程

  • 5个线程互斥显示数组数字,当其中一个线程在显示时,其他线程无法显示,直接退出
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

// 声明并且初始化锁(互斥锁)
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
 
int tf[5];
 
void* print(void* i)
{
    /********************************************
    * 如果改为 int flag = pthread_mutex_lock(&mut); 
    * 则为阻塞的,该线程会被加入队列等待开锁 
    ********************************************/

    /**************************************************
    * 非阻塞如果不为零说明有其他线程正在进行,即不应该执行该线程
    * 因此可以判断flag并退出该线程
    **************************************************/
    int *id = (int*)i;

    int flag = pthread_mutex_trylock(&mut);
    if (flag==0)
    {
        sleep(1);
        for (int j=0;j<5;j++)
            printf("thread %d: %d\n", *id, j);
        pthread_mutex_unlock(&mut);
    }
    else
    {
        printf("thread %d: 其他线程正在进行\n", *id);
    }
}

int main()
{
    pthread_t td[5]; // 初始化线程
    for(int i=0;i<5;i++)
        tf[i] = i;
    for(int i=0;i<5;i++)
        // 创建线程
        pthread_create(&td[i],NULL,print,(void *)&tf[i]);
    for(int i=0;i<5;i++)
    {
        // 运行线程,join函数确保子线程执行完了主程序才退出
        pthread_join(td[i],NULL);
    }
    pthread_mutex_destroy(&mut);
}

条件锁

条件锁就是所谓的条件变量,某一个线程因为某个条件为满足时可以使用条件变量使改程序处于阻塞状态。一旦条件满足以“信号量”的方式唤醒一个因为该条件而被阻塞的线程。

头文件:<pthread.h>
类型:pthread_cond_t

  • pthread_cond_wait:线程阻塞在条件变量
  • pthread_cond_signal:线程被唤醒

linux C++ 多线程使用pthread_cond 条件变量
线程属性pthread_attr_t简介

例程

  • 线程0、线程1互斥加一个数,加一次唤醒一次条件触发的线程2,如果线程2处于阻塞等待状态则被唤醒
  • 线程2判断数值大小时,给线程0、1上锁,停止加数,当数字小于10时,等待3秒,否则加100退出该线程
  • 线程0、1各加10次退出线程,线程2检测到数字大于10加100后退出线程,三个线程都结束程序退出
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

#define NUM_THREADS 3 
#define TCOUNT      10 
#define COUNT_LIMIT 10 

int count = 0;
int thread_ids[3] = {0,1,2};
pthread_mutex_t count_mutex;  // 计数时上锁
pthread_cond_t  count_threshold_cv;

void *inc_count(void *idp)
{
    int i = 0;
    int taskid = 0;
    int *my_id = (int*)idp;

    for (i=0; i<TCOUNT; i++) {
        // 互斥锁上锁
        pthread_mutex_lock(&count_mutex);
        taskid = count;
        count++;

        /*
          唤醒一个阻塞在该条件变量的线程
          如果没有线程被阻塞在条件变量上,那么调用pthread_cond_signal()将没有作用
        */
        pthread_cond_signal(&count_threshold_cv);

        printf("inc_count(): thread %d, count = %d, 开互斥锁\n", *my_id, count);
        // 互斥锁解锁
        pthread_mutex_unlock(&count_mutex);
        sleep(1);
    }
    printf("inc_count(): thread %d, Threshold reached.\n", *my_id);

    pthread_exit(NULL);
}

void *watch_count(void *idp)
{
    int *my_id = (int*)idp;
    printf("Starting watch_count(): thread %d\n", *my_id);

    pthread_mutex_lock(&count_mutex);
    while(count<COUNT_LIMIT) {
        sleep(3); 
        /*
          函数将自动/原子到解锁mutex参数指向的互斥锁,
          并使当前线程阻塞在cv参数指向的条件变量上
          被阻塞的线程可以被pthread_cond_signal函数,
          pthread_cond_broadcast函数唤醒,
          也可能在被信号中断后被唤醒
          pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,
          必须重新检查条件的值. 
          本例子中使用类COUNT_LIMIT最为满足条件的值
          pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,
          即使是函数出错返回
        */
        pthread_cond_wait(&count_threshold_cv, &count_mutex);
        printf("watch_count(): thread %d 收到条件信号.\n", *my_id);
    }

    count += 100;
    pthread_mutex_unlock(&count_mutex);
    pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
    int i, rc;
    pthread_t threads[3];
    pthread_attr_t attr; // 线程属性

    /* Initialize mutex and condition variable objects */
    pthread_mutex_init(&count_mutex, NULL);
    pthread_cond_init (&count_threshold_cv, NULL);

    /* For portability, explicitly create threads in a joinable state */
    pthread_attr_init(&attr);  // 对线程属性变量的初始化
    /*
    设置线程detachstate属性。该表示新线程是否与进程中其他线程脱离同步,
    如果设置为PTHREAD_CREATE_DETACHED则新线程不能用pthread_join()来同步,
    且在退出时自行释放所占用的资源。缺省为PTHREAD_CREATE_JOINABLE状态。
    这个属性也可以在线程创建并运行以后用pthread_detach()来设置,
    而一旦设置为PTHREAD_CREATE_DETACH状态(不论是创建时设置还是运行时设置)
    则不能再恢复到PTHREAD_CREATE_JOINABLE状态。
    */
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    pthread_create(&threads[0], &attr, inc_count,   (void *)&thread_ids[0]);
    pthread_create(&threads[1], &attr, inc_count,   (void *)&thread_ids[1]);
    pthread_create(&threads[2], &attr, watch_count, (void *)&thread_ids[2]);

    /* Wait for all threads to complete */
    for (i=0; i<NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }
    printf ("Main(): Waited on %d  threads. Done.\n", NUM_THREADS);

    /* Clean up and exit */
    pthread_attr_destroy(&attr);
    pthread_mutex_destroy(&count_mutex);
    pthread_cond_destroy(&count_threshold_cv);
    pthread_exit(NULL);

    return 0;
}

自旋锁

当发生阻塞时,互斥锁可以让CPU去处理其他的任务;而自旋锁让CPU一直不断循环请求获取这个锁,它会一直占用CPU请求这个自旋锁使得CPU不能去做其他的事情,直到获取这个锁为止,比较耗费CPU

头文件:<pthread.h>
类型:pthread_spinlock_t

  • 初始化:pthread_spin_init(pthread_spinlock_t *__lock, int __pshared);
  • pthread_spin_lock(x); //只有在获得锁的情况下才返回,否则一直“自旋”
  • pthread_spin_trylock(x); //如果该锁已经被争用,那么该函数立即返回一个非0值,而不会自旋等待锁被释放;
  • 释放锁:phtread_spin_unlock(x);
  • 释放资源:pthread_spin_destroy(&lock);

注意:自旋锁适合于短时间的的轻量级的加锁机制

代码同互斥锁,更改init、lock、unlock、destroy即可

...保持更新中

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,783评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,396评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,834评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,036评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,035评论 5 362
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,242评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,727评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,376评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,415评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,463评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,140评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,734评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,809评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,028评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,521评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,119评论 2 341

推荐阅读更多精彩内容