C语言细致讲解线程同步的集中方式

目录
  • 互斥锁
  • 条件变量
  • 信号量
  • 读写锁

互斥锁

使用互斥量完成对临界区的资源的加锁操作,使得同一时刻,对一个共享数据的使用只能又一个线程完成

例向屏幕上一次打印abcd四个字母

可以使用的是一个类似锁连的思想 a 加完解开后拿b锁依次类推

#define THRNUM 4
static pthread_mutex_t mut[4];
static int next(int n)
{
    if(n + 1 == THRNUM)
    return 0;
    return n+1;
}
static void* pthreadfunc(void* p)
{
    int n =(int)p;
    char c = 'a' + (int)p;
    while(1)
    {
    pthread_mutex_lock(mut + n);
    write(1,&c,1);
    pthread_mutex_unlock(mut + next(n));
    }
    pthread_exit(NULL);
}
int main()
{
    int i,err;
    pthread_t tid[THRNUM];
    //创建线程
    for(i = 0 ; i < THRNUM ;i++){
        //初始化锁
        pthread_mutex_init(mut + i,NULL);
        //加锁
        pthread_mutex_lock(mut+i );
    err = pthread_create(tid+i,NULL,pthreadfunc,(void*)i );
    if(err != 0)
    {
        fprintf(stderr,"create:%s\n",strerror(err));
        exit(1);
    }
    }
    //回收线程
    pthread_mutex_unlock(mut + 0);
    alarm(5);
    for(i = 0 ; i < THRNUM ;i++){
    pthread_join(tid+i,NULL);
    }
}

条件变量

条件变量并不是锁而是一种阻塞机制,使得我们的程序在某些特定的条件,比如生产者生产达到上限未消费,此时使用条件变量(加上while对条件的判断)来阻塞生产,让生产者消费

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
int begnum=0;
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  cond = PTHREAD_COND_INITIALIZER;
typedef struct _prodinfo
{
    int num;
    struct _prodinfo *next;
}prod;
struct _prodinfo* head=NULL;
/*  条件变量可以引起阻塞并非锁
*/
void *thr_produce(void*arg)
{
    while(1)
    {
        prod* pd = malloc(sizeof(struct _prodinfo));
        pd->num=begnum++;
        pthread_mutex_lock(&mut);
        pd->next=head;
        head=pd;
        printf(" -%ld号线程生产%d产品\n",pthread_self(),pd->num);
        pthread_mutex_unlock(&mut);
        pthread_cond_signal(&cond);
        sleep(rand()%4);
    }
}
void* thr_con(void* arg)
{
    prod* pro=NULL;
    while(1)
    {
        pthread_mutex_lock(&mut);
        while(head==NULL)
            pthread_cond_wait(&cond,&mut);
        pro = head;
        head=head->next;
        printf(" -%ld号线程消费%d产品\n",pthread_self(),pro->num);
        pthread_mutex_unlock(&mut);
        free(pro);
        sleep(rand()%4);
    }
}
int main()
{
    pthread_t cid,pid;
    int err1=pthread_create(&pid,NULL,thr_produce,NULL);
     if(err1)
        {
            fprintf(stderr,"pthread_creat():%s\n",strerror(err1));
            exit(1);
        }
    int err2=pthread_create(&cid,NULL,thr_con,NULL);
      if(err2)
        {
            fprintf(stderr,"pthread_creat():%s\n",strerror(err1));
            exit(1);
        }
    pthread_join(pid,NULL);
    pthread_join(cid,NULL);
}

信号量

介绍以下信号量是进化版的互斥量,允许多个线程访问共享资源与条件变量和互斥量类此的操作,在进程和线程中均可以使用

int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t *sem);
Link with -pthread.

sem为定义的信号量,传出型参数

pshared

  • 0 代表线程信号量
  • 1 代表进程信号量

alue 为定义的信号量个数

    int sem_wait(sem_t *sem);
    int sem_trywait(sem_t *sem);
    int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

申请信号量,申请成功value–,当value为0 则阻塞

 int sem_post(sem_t *sem);

释放信号量value++

例 信号量实现生产者消费者模型

sem_t pro_sem,con_sem;
#define semcnt 5
int i=0;
int queue[semcnt];
int beginnum = 100;
void *thr_produce(void*arg)
{
    while(1)
    {
        sem_wait(&pro_sem);//生产者申请资源 pro_sem每被占用一次--一次 当为0时则阻塞
        printf("%ld 线程生产了 %d\n",pthread_self(),beginnum);
        queue[(i++)%semcnt]= beginnum++;
        sem_post(&con_sem);//为消费者的信号量释放资源pro_sem每被释放一次++一次
        sleep(rand()%4);
    }
    return NULL;
}
void* thr_con(void* arg)
{
    int i=0;
    int num=0;
    while(1)
    {
        sem_wait(&con_sem);
        num = queue[(i++)%semcnt];
        printf("%ld 线程消费了 %d\n",pthread_self(),num);
        sem_post(&pro_sem);
        sleep(rand()%3);
    }
    return NULL;
}
int main()
{
    sem_init(&pro_sem,0,semcnt);
    sem_init(&con_sem,0,0); //消费者初始默认没有产品
    pthread_t tid[2];
     int err1=pthread_create(&tid[0],NULL,thr_produce,NULL);
     if(err1)
        {
            fprintf(stderr,"pthread_creat():%s\n",strerror(err1));
            exit(1);
        }
    int err2=pthread_create(&tid[1],NULL,thr_con,NULL);
      if(err2)
        {
            fprintf(stderr,"pthread_creat():%s\n",strerror(err1));
            exit(1);
        }
        pthread_join(tid[0],NULL);
        pthread_join(tid[1],NULL);
    sem_destroy(&pro_sem);
    sem_destroy(&con_sem);
}

读写锁

读写锁 与互斥量类似,但是读写锁允许更高的并行性,其特性为:写独占,读共享

读写锁实质上是一把锁,有不同的状态,写锁的优先级高

读写锁的三种状态

  • 读模式下加锁(读锁)
  • 写模式下加锁(写锁)
  • 不加锁状态

读写锁的特性: 读锁可以共享读的状态,当读锁加上时,阻塞写锁的加锁

即使读锁加上时 后面的 写锁依然会被阻塞,当前面读锁释放时才能加成功

pthread_rwlock_t rwlock =PTHREAD_RWLOCK_INITIALIZER;
int beginum=100;
void*thr_Wr(void*arg)
{
    while(1)
    {
        pthread_rwlock_wrlock(&rwlock);
        printf("-写线程--beginum = %d\n",beginum++);
        usleep(2000);//模拟占用时间
        pthread_rwlock_unlock(&rwlock);
        usleep(2000);//简单防止再抢锁的方法但不建议使用
    }
    return NULL;
}
void*thr_ead(void*arg)
{
    while (1)
    {
        pthread_rwlock_rdlock(&rwlock);
      printf("-读读线程--beginum = %d\n",beginum);
        usleep(2000);//模拟占用时间
       pthread_rwlock_unlock(&rwlock);
        usleep(2000);//简单防止再抢锁的方法但不建议使用
    }
    return NULL;
}
int main()
{
    int n=8,i=0;
    pthread_t tid[8];
    for(i = 0; i<5;i++)
    {
        pthread_create(&tid[i],NULL,thr_ead,NULL);
    }
     for(; i<8;i++)
    {
        pthread_create(&tid[i],NULL,thr_Wr,NULL);
    }
     for(i = 0; i<8;i++)
    {
        pthread_join(tid[i],NULL);
    }
   pthread_rwlock_destroy(&rwlock);
}

到此这篇关于C语言细致讲解线程同步的集中方式的文章就介绍到这了,更多相关C语言线程同步内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++详解多线程中的线程同步与互斥量

    目录 线程同步 互斥量 线程同步 /* 使用多线程实现买票的案例. 有3个窗口,一共是100张票. */ #include <stdio.h> #include <pthread.h> #include <unistd.h> // 全局变量,所有的线程都共享这一份资源. int tickets = 100; void * sellticket(void * arg) { // 卖票 while(tickets > 0) { usleep(6000); //微秒 p

  • C++ 如何实现多线程与线程同步

    CreateThread 实现多线程: 先来创建一个简单的多线程实例,无参数传递版,运行实例会发现,主线程与子线程运行无规律. #include <windows.h> #include <iostream> using namespace std; DWORD WINAPI Func(LPVOID lpParamter) { for (int x = 0; x < 10; x++) { cout << "thread function" &l

  • C语言细致讲解线程同步的集中方式

    目录 互斥锁 条件变量 信号量 读写锁 互斥锁 使用互斥量完成对临界区的资源的加锁操作,使得同一时刻,对一个共享数据的使用只能又一个线程完成 例向屏幕上一次打印abcd四个字母 可以使用的是一个类似锁连的思想 a 加完解开后拿b锁依次类推 #define THRNUM 4 static pthread_mutex_t mut[4]; static int next(int n) { if(n + 1 == THRNUM) return 0; return n+1; } static void*

  • C语言由浅入深讲解线程的定义

    目录 线程的概念 线程的创建 线程的终止 线程标识的比较 线程的取消 线程等待 线程分离 线程的概念 可以简单理解为一个正在独立运行的函数 注: 1.posix线程是一套标准吗,而不是实现 2.线程标识: phread_t,可能是整形也可能是结构体指针等 *简单介绍关于线程标识的函数* *pthread_equarl() ;判断两个线程标识是否相等**pthread_self():返回自身的线程标识* 线程的创建 pthread_creat(); int pthread_create( pthr

  • java多线程之线程同步七种方式代码示例

    为何要使用同步?  java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),     将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,     从而保证了该变量的唯一性和准确性. 1.同步方法  即有synchronized关键字修饰的方法.     由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,     内置锁会保护整个方法.在调用该方法前,需要获得内置锁,否则就处于阻塞状态.     代码

  • 详解易语言线程同步

    在易语言官方多线程支持库中提供线程同步的方法是用许可区. 加入许可区之后可以防止多个线程同时访问公用变量是发生冲突.加入许可区的代码同时只能有一个线程访问,避免冲突. 创建许可区: 创建并返回一个进入许可证数值,此许可证值用作进入程序中的指定许可代码区,以避免多线程冲突.成功返回非零整数值,失败返回0.所创建的许可证在不再使用后,必须使用"删除进入许可证"命令将其删除.本命令为初级命令. 删除进入许可证: 删除由"创建进入许可证"命令所创建返回的进入许可证.成功返回

  • 利用synchronized实现线程同步的案例讲解

    一.前期基础知识储备 (1)线程同步的定义:多线程之间的同步. (2)多线程同步原因:一个多线程的程序如果是通过Runnable接口实现的,则意味着类中的属性将被多个线程共享,由此引出资源的同步问题,即当多个线程要操作同一资源时,有可能出现错误. (3)实现多线程同步的方式--引入同步机制:在线程使用一个资源时为其加锁,这样其他的线程便不能访问那个资源了,直到解锁后才可以访问.--这样做的结果,所有线程间会有资源竞争,但是所有竞争的资源是同步的,刷新的,动态的,不会因为线程间的竞争,导致资源"过

  • Java 详细讲解线程安全与同步附实例与注释

    目录 线程安全问题 实例: 存钱取钱问题 买票问题 线程安全问题 分析问题 解决方案 线程同步 同步语句 synchronize(obj)的原理 同步方法 同步方法的本质 线程安全问题 多个线程可能会共享(访问)同一个资源 比如访问同一个对象,同一个变量,同一个文件 当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题,称为线程安全问题 什么情况下会出现线程安全问题 多个线程共享同一个资源 且至少有一个线程正在执行写的操作 实例: 存钱取钱问题 分别有存钱和取钱2个线程 存钱      

  • C语言深入细致讲解动态内存管理

    目录 为什么存在动态内存管理 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 对NULL指针的解引用操作 对动态开辟空间的越界访问 对非动态开辟内存使用free访问 使用free 释放一块动态开辟内存的一部分 对一块动态内存多次释放 对动态内存开辟忘记释放 柔性数组 小结 为什么存在动态内存管理 我们已经掌握的内存开辟方式有: int val = 20;//在栈空间上开辟四个字节 char arr[10] = { 0 };//在栈空间上开辟10个字节

  • C语言全面细致讲解文件操作

    目录 什么是文件 程序文件 数据文件 文件名 文件指针 文件的打开和关闭 文件的顺序读写 字符输入输出函数 字符串输入输出函数(fgets,fputs) 格式化输入输出函数(fscanf,fprintf) 二进制输入输出函数(fread,fwrite) 文件的随机读写 fseek ftell 文件读取结束的判定 什么是文件 磁盘上的文件是文件.但是在程序设计中,我们一般谈的文件有两种:程序文件.数据文件(从文件功能的角度来分类的). 程序文件 包括源程序文件(后缀为.c),目标文件(window

  • C语言全面细致讲解单双精度float与double的使用方法

    目录 一.float与double类型介绍 二.例题 三.总结 一.float与double类型介绍 代码: #include <stdio.h> int main (void) { float a=3.14159261111; //单精度浮点型 double b=3.14159261111; //双精度浮点型 printf("数值1:%f\n",a); // 单精度符号%f ,默认保留六位小数 printf("数值2:%.2f\n",a); // %.

  • Java全面细致讲解类与对象

    目录 类和对象的关系 类和对象的实例化 static关键字 private实现的封装 构造方法 this关键字 代码块 匿名对象 小结 类和对象的关系 类就是一类对象的统称.对象就是这一类具体化的一个实例. (对象是类的实例化) 对象是什么? 此对象非彼对象!!!说到对象就要提到过程. 面向过程:C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题.面向过程注重的是过程,在整个过程中所涉及的行为,就是功能. 面向对象:JAVA是基于面向对象的,关注的是对象,将一件事情

随机推荐