多线程锁

1. 背景知识:
多线程中经常需要使用到锁(pthread_mutex_t)来完成多个线程之间的某些同步操作
• 互斥锁:为了使不同线程互斥的使用某个资源
    ○ 锁的创建:pthread_mutex_init
        § pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
        § int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t * attr);
    ○ 锁的属性:
        pthread_mutexattr_init(pthread_mutexattr_t *mattr)
        pthread_mutexattr_settype(pthread_mutexattr_t *attr , int type)
        pthread_mutexattr_gettype(pthread_mutexattr_t *attr , int *type)
        § 普通锁:PTHREAD_MUTEX_TIMED_NP(当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性)
        § 嵌套锁:PTHREAD_MUTEX_RECURSIVE_NP(允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争)
        § 检错锁:PTHREAD_MUTEX_ERRORCHECK_NP(如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁)
        § 适应锁:PTHREAD_MUTEX_ADAPTIVE_NP(动作最简单的锁类型,仅等待解锁后重新竞争)
    ○ 锁的释放:pthread_mutex_destory
    ○ 锁操作:
        § 加锁:int pthread_mutex_lock(pthread_mutex_t *mutex)
        § 解锁:int pthread_mutex_unlock(pthread_mutex_t *mutex)
        § 测试加锁:int pthread_mutex_trylock(pthread_mutex_t *mutex)
• 条件锁:为了保证不同线程之间有顺序(通过条件控制)地完成某个流程
    ○ 等待方式:
        § 无条件等待:pthread_cond_wait()
        § 计时等待:pthread_cond_timedwait()
    ○ 激活条件:
        §  int pthread_cond_signal(pthread_cond_t *cond); 激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个
        § int pthread_cond_broadcast(pthread_cond_t *cond);  激活所有等待线程

互斥锁:

#include <pthread.h>
#include <stdio.h>
 
pthread_mutex_t mutex ;
void *print_msg(void *arg){
        int i=0;
        pthread_mutex_lock(&mutex);
        for(i=0;i<15;i++){
                printf("output : %d\n",i);
                usleep(100);
        }
        pthread_mutex_unlock(&mutex);
}
int main(int argc,char** argv){
        pthread_t id1;
        pthread_t id2;
        pthread_mutex_init(&mutex,NULL);
        pthread_create(&id1,NULL,print_msg,NULL);
        pthread_create(&id2,NULL,print_msg,NULL);
        pthread_join(id1,NULL);
        pthread_join(id2,NULL);
        pthread_mutex_destroy(&mutex);
        return 1;
}

条件锁:

//一个生产者消费者模型
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>

typedef struct node
{
    int num;
    struct node *next;
} node_t;

typedef node_t *list_t;
list_t head = NULL;
pthread_mutex_t mutex =
    PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond =
    PTHREAD_COND_INITIALIZER;

//消费者线程
void *consume(void *arg)
{
    node_t *tmp;
    while (1)
    {
        //加锁
        pthread_mutex_lock(&mutex); //对临界变量加锁
        if (head == NULL)           //如果头部指向空,等待
            pthread_cond_wait(&cond, &mutex);
        tmp = head;        //将要删除的节点赋值给中间值,然后头指针指向下一个
        head = head->next; //
        //解锁
        pthread_mutex_unlock(&mutex);
        //消费tmp节点
        printf("consum:%d\n", tmp->num);
        free(tmp);
        tmp = NULL;
        sleep(rand() % 5);
    }
}

//生产者线程
void *product(void *arg)
{ //函数的格式void *(*start_routine) (void *),返回值是指针,参数也是
    node_t *n;
    while (1)
    {
        //生产一个新的节点
        n = (node_t *)malloc(sizeof(node_t));
        n->num = rand() % 1000 + 1;
        printf("p:%d\n", n->num);
        //加锁
        pthread_mutex_lock(&mutex);
        //将新节点放入到链表的头部
        n->next = head;
        head = n;
        //解锁
        pthread_mutex_unlock(&mutex);
        //通知消费者
        pthread_cond_signal(&cond);
        sleep(rand() % 5);
    }
}
int main(void)
{
    pthread_t pid, cid;
    //设置随机数的种子
    srand(time(NULL));
    //创建两个线程,用于生产者和消费者
    pthread_create(&pid, NULL, product, NULL); //创建线程后即执行该线程
    pthread_create(&cid, NULL, consume, NULL); //参数含义是(存放ID的缓存区,NULL缺省属性,线程的执行函数,函数的唯一参数)
    //等待线程的汇合
    pthread_join(pid, NULL);
    pthread_join(cid, NULL);
    //销毁mutex锁
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352

推荐阅读更多精彩内容

  • ps: 这篇文章看资料时头疼,写起来时更头疼,写完了说实话也没多大用,充其量也就是多了解了一些锁的内容,也许扣字眼...
    前行的乌龟阅读 1,525评论 0 5
  • 线程锁 使用多线程能提高程序的执行效率,但也同时也给程序带来一些线程安全上面的问题,比如是数据竞争关系(data ...
    struggle3g阅读 2,183评论 1 2
  • 多线程需要一种互斥的机制来访问共享资源。 一、 互斥锁 互斥锁的意思是某一时刻只允许一个线程访问某一资源。为了保证...
    doudo阅读 731评论 0 5
  • 参考链接:http://smallbug-vip.iteye.com/blog/2275743 在多线程开发的过程...
    时之令阅读 1,553评论 2 5
  • 题记:虽然有些事情的发生可能是你预料之中的,但是当它真正的发生了的时候,还是很难以接受的,还是需要一点时间,去缓和...
    LynnXYT阅读 2,001评论 4 16