线程同步与互斥

Linux--线程编程
多线程编程-互斥锁

线程同步与互斥

  1. 互斥锁
  2. 信号量
  3. 条件变量

互斥锁

#include <pthread.h>
    互斥锁静态初始化:pthread_mutex_t mtx=PTHREAD_MUTEX_INITIALIZER
   互斥动态锁初始化:pthread_mutex_init()
  互斥锁上锁:  pthread_mutex_lock()
  互斥锁判断上锁:pthread_mutex_trylock()
  互斥锁解锁:pthread_mutex_unlock()
  消除互斥锁:pthread_mutex_destroy()
 int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
 int pthread_mutex_lock(pthread_mutex_t *mutex);
 int pthread_mutex_unlock(pthread_mutex_t *mutex);
 int pthread_mutex_destroy(pthread_mutex_t *mutex);
pthread_mutex_init()

互斥锁的基本使用

互斥量既可以像静态变量那样分配,也可以在运行时动态创建(例如,通过malloc()在一块内存中分配)。动态互斥量的创建稍微有些复杂。

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>


void *thread1_fun(void*arg);

typedef struct arry_int
{
    int *a;
    int numb;
}ARRY_INT;

void reverse(int a[],int numb);

static pthread_mutex_t testlock;


int main(int argc, char const *argv[])
{
    pthread_t  thread1;
    pthread_mutex_init(&testlock, NULL);

    int a[20]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
    ARRY_INT a_int={a,sizeof(a)/sizeof(int)};

    //创建线程
    int ret=pthread_create(&thread1,NULL,thread1_fun,&a_int);
    if (ret!=0)
    {
        perror("pthread_create wrong");
        exit(EXIT_FAILURE);
    }

    while(1)
    {
        // 启动锁
        pthread_mutex_lock(&testlock);

        for (int i = 0; i < 20; ++i)
            printf("%d ",a[i]);
        // 解锁
        pthread_mutex_unlock(&testlock);
        printf("\n");
        sleep(1);

    }
    return 0;
}


void *thread1_fun(void*arg)
{
    ARRY_INT *a=(ARRY_INT*)arg;
    while(1)
    {
        pthread_mutex_lock(&testlock);
        reverse(a->a,a->numb);
        pthread_mutex_unlock(&testlock);
        sleep(1);
    }

    return NULL;
}



void reverse(int a[],int numb)
{
    int tem;
    for (int i = 0; i<numb-i; ++i)
    {
        tem=a[i];
        a[i]=a[numb-1-i];
        a[numb-1-i]=tem;
        // printf("%d\n", i);
    }
    return;
}

信号量

       #include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);
创建一个信号量,并初始化它

  • sem:初始化一个信号量结构体在sem地址处
  • pshared:0为线程间共享信号量 1为进程间共享信号量 (但linux没有实现)
  • value:信号量的初始值

int sem_wait(sem_t *sem)  
int sem_trywait(sem_t *sem): P操作,在信号量大于零时将信号量的值减一   
区别: 若信号量小于零时,sem_wait()将会阻塞线程,sem_trywait()则会立即返回  

int sem_post(sem_t *sem): V操作,将信号量的值加一同时发出信号来唤醒等待的线程  

int sem_getvalue(sem_t *sem): 得到信号量的值  
int sem_destroy(sem_t *sem): 删除信号量

RETURN VALUE
All of these functions return 0 on success; on error, the value of the semaphore is left unchanged, -1 is returned, and errno is set to indicate the error.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

#define THREAD_NUM 3
#define REPEAT_TIMES 5
#define DELAY 4

sem_t sem[THREAD_NUM];

void *thrd_func(void *arg);

int main(){
    pthread_t thread[THREAD_NUM];
    int no;
    void *tret;
    
    srand((int)time(0)); 

    // 初始化THREAD_NUM-1个信号量,均初始化为0
    for(no=0;no<THREAD_NUM-1;no++){
        sem_init(&sem[no],0,0);
    }

    // sem[2]信号量初始化为1,即sem数组中最后一个信号量
    sem_init(&sem[2],0,1);
    
    // 创建THREAD_NUM个线程,入口函数均为thrd_func,参数为(void*)no
    for(no=0;no<THREAD_NUM;no++){
        if (pthread_create(&thread[no],NULL,thrd_func,(void*)no)!=0) {
            printf("Create thread %d error!\n",no);
            exit(1);
        } else
            printf("Create thread %d success!\n",no);
    }
    
    // 逐个join掉THREAD_NUM个线程
    for(no=0;no<THREAD_NUM;no++){
        if (pthread_join(thread[no],&tret)!=0){
            printf("Join thread %d error!\n",no);
            exit(1);
        }else
            printf("Join thread %d success!\n",no);
    }
    
    // 逐个取消信号量
    for(no=0;no<THREAD_NUM;no++){
        sem_destroy(&sem[no]);
    }

    return 0;
}

void *thrd_func(void *arg){
    int thrd_num=(void*)arg; // 参数no
    int delay_time,count;

    // 带有阻塞的p操作
    sem_wait(&sem[thrd_num]);

    
    printf("Thread %d is starting.\n",thrd_num);
    for(count=0;count<REPEAT_TIMES;count++) {
        delay_time=(int)(DELAY*(rand()/(double)RAND_MAX))+1;
        sleep(delay_time);
        printf("\tThread %d:job %d delay =%d.\n",thrd_num,count,delay_time);
    }

    printf("Thread %d is exiting.\n",thrd_num);
    
    // 对前一个信号量进行V操作
    // 由于只有最后一个信号量初始化为1,其余均为0
    // 故线程执行的顺序将为逆序
    sem_post(&sem[(thrd_num+THREAD_NUM-1)%THREAD_NUM]);

    pthread_exit(NULL); // 线程主动结束
}

条件变量

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

推荐阅读更多精彩内容