Linux-线程-信号量-互斥锁

一.进程基础

1.线程:进程内部的一条执行路径(序列),一个进程可以包含多个线程     进程:一个正在运行的程序

2.创建线程:pthread_create()

   退出线程:pthread_exit()  --->退出进程:exit()

   等待线程结束:pthread_join

3.一个函数对应一个线程

4. int pthread_create(pthread_t *thread(线程id),const pthred_attr_t*attr(线程属性一般不设置,填NULL即可),void*(*start_routine)(void*)(线程函数,有几个线程就创建几个线程函数,参数为void*,返回值为void*的函数指针),void*arg(线程函数的参数))----->创建线程

    int pthread_join(pthread_t thread(线程id),void**retval(接收线程函数返回主线程的一些信息))--->等待线程结束,线程未结束会阻塞住

    int pthread_t exit(void *retval(传一个信息给主线程))--->退出线程

5.线程编译:

6.两个线程并发进行子线程与主线程同时进行,子线程与子线程同时进行,并不是函数调用

#include<stdio.h>
#include<pthread.h>//线程的头文件

void*fun(void*arg)//线程函数,返回值为void*类型,参数为void*类型
{
    for(int i=0;i<5;i++)
    {
        printf("fun run\n");
        sleep(1);
    }
    pthread_t exit("fun over");//传给指针s
}
int main()
{
    pthread_t id;//定义线程Id
    pthread_create(&id,NULL,fun,NULL);//第二个NULL为传给线程函数的参数
    
    for(int i=0;i<5;i++)
    {
        printf("main run\n");
        sleep(1);
    }
    char *s=NULL;
    pthread_join(id,(void**)&s);//接收s若子线程未结束则阻塞
    pthread_join(id,NULL);//子线程未结束则阻塞,不用接收返回值
    printf("s=%s\n",s);
     
    exit(0);
}

7.进程并行:并发运行-->交替进行(1个处理器) 并行:-->同时进行(2个以上处理器) 

①没次打印的值是随机的,并不一定是0-4,可能有重复的

#include<stdio.h>
#include<pthread.h>//线程的头文件  有多个处理器可以多个执行,单个处理器单个执行

void*fun(void*arg)//线程函数,返回值为void*类型,参数为void*类型  创建好5个线程但调度执行顺序是随机的
{
   int *p=(int*)arg;
   int index=*p;
   printf("index=%d\n",index);
}
int main()
{
    pthread_t id[5];//定义5个线程Id  

    int i=0;
    for(;i<5;i++)
    {
        pthread_create(&id[i],NULL,fun,&i);//传id[i]的地址,将id存入数组中
    }
    for(i=0;i<5;i++)
    {
        pthread_join(id,NULL);//子线程未结束则阻塞,不用接收返回值
    }
    exit(0);
}

②这样改后就不会出现随机,只会是0-4

#include<stdio.h>
#include<pthread.h>//线程的头文件  有多个处理器可以多个执行,单个处理器单个执行

void*fun(void*arg)//线程函数,返回值为void*类型,参数为void*类型  创建好5个线程但调度执行顺序是随机的
{
   int *p=(int*)arg;
   int index=*p;
   printf("index=%d\n",index);
   free(p);//此时p指向malloc所指向的空间
}
int main()
{
    pthread_t id[5];//定义5个线程Id  

    int i=0;
    for(;i<5;i++)
    {
        int *s=(int*)malloc(sizeof(int));//申请空间将i的值给到堆区空间
        *s=i;
        pthread_create(&id[i],NULL,fun,(void*)s);//传id[i]的地址,将id存入数组中
    }
    for(i=0;i<5;i++)
    {
        pthread_join(id,NULL);//子线程未结束则阻塞,不用接收返回值
    }
    exit(0);
}

③从1开始创建5个线程,每个线程加1000,在多个处理器下,结果可能小于等于5000,原因是在多个线程运行时,不同的处理器可能同时进行一个操作,导致有重复的数出现,结果小于了5000

#include<stdio.h>
#include<pthread.h>//线程的头文件  有多个处理器可以多个执行,单个处理器单个执行

int g_val=1;
void*fun(void*arg)//线程函数,返回值为void*类型,参数为void*类型  创建好5个线程但调度执行顺序是随机的
{
    for(int i=0;i<1000;i++)
    {
        printf("g_val=%d\n",g_val++);
    }
}
int main()
{
    pthread_t id[5];//定义5个线程Id  

    int i=0;
    for(;i<5;i++)
    {
        pthread_create(&id[i],NULL,fun,NULL);//传id[i]的地址,将id存入数组中
    }
    for(i=0;i<5;i++)
    {
        pthread_join(id,NULL);//子线程未结束则阻塞,不用接收返回值
    }
    exit(0);
}

8    ./main >file.txt  (将结果写到一个文件中)

9.查看文件中重复的值:uniq -d file.txt(-d只会查看重复行)

二.线程同步

1.线程同步:信号量,互斥锁,读写锁,条件变量

2.信号量:初始值可以自己设置,有顺序的就用信号量

     sem_init(sem_t*sem(信号量地址),int pshared(能否在两个进程间共享,一般为0),unsigned int value(初始值))-->初始化

     sem_wait(sem_t*sem(信号量地址))-->p操作 获取资源

     sem_post(sem_t*sem(信号量地址))-->v操作 释放资源

     sem_destroy(sem_t*sem(信号量地址))-->销毁

3.互斥锁:解决互斥性场所,信号量也可以满足这个,不要求顺序可以用互斥锁

     pthread_mutex_init(pthread_mutex_t * restrict mutex(锁变量地址),const pthread_mutexattr_t *restrict attr(属性,一般给NULL))-->初始化互斥锁

     pthread_mutex_lock(pthread_mutex_t *mutex(锁变量地址))-->加锁,阻塞

     pthread_mutex_unlock(pthread_mutex_t *mutex(锁变量地址))-->解锁

     pthread_mutex_destroy(pthread_mutex_t *mutex(锁变量地址))-->销毁锁

4.使用信号量与互斥锁解决:从1开始创建5个线程,每个线程加1000,在多个处理器下,使结果等于5000

#include<stdio.h>
#include<pthread.h>//线程的头文件  有多个处理器可以多个执行,单个处理器单个执行
#incldue<semaphore.h>//线程信号量头文件

//sem_t sem;//信号量
pthread_mutex_t metux//锁变量

int g_val=1;
void*fun(void*arg)//线程函数,返回值为void*类型,参数为void*类型 
{
    for(int i=0;i<1000;i++)
    {
        //sem_wait(&sem);//p操作
        pthread_mutex_lock(&metux);//加锁
        
        printf("g_val=%d\n",g_val++);

        pthread_mutex_unlock(&metux);//解锁
        //sem_post(&sem);//v操作
    }
}
int main()
{
    pthread_t id[5];//定义5个线程Id  

    //sem_init(&sem,0,1);//0为不能在两个进程间共享,1为信号量初始值为1
    //pthread_mutex_init(&metux,NULL);

    int i=0;
    for(;i<5;i++)
    {
        pthread_create(&id[i],NULL,fun,NULL);//传id[i]的地址,将id存入数组中
    }
    for(i=0;i<5;i++)
    {
        pthread_join(id,NULL);//子线程未结束则阻塞,不用接收返回值
    }

    pthread_mutex_destroy(&metux);
    //sem_destroy(&sem);
    exit(0);
}

5.三条执行路径打印ABC ABC ABC ABC ABC

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

sem_t sema;
sem_t semb;
sem_t semc;

void* funa(void* arg)
{
    for(int i = 0; i < 5; i++ )
    {
        sem_wait(&sema);//ps1
        printf("A");
        fflush(stdout);
        sem_post(&semb);//vs2
    }
}

void * funb(void* arg)
{
    for(int i = 0; i < 5; i++ )
    {
        sem_wait(&semb);//ps2
        printf("B");
        fflush(stdout);
        sem_post(&semc);//vs3
    }
}

void * func(void* arg)
{
    for(int i = 0; i < 5; i++ )
    {
        sem_wait(&semc);//ps3
        printf("C");
        fflush(stdout);
        sem_post(&sema);//vs1
    }
}
int main()
{
    sem_init(&sema,0,1);
    sem_init(&semb,0,0);
    sem_init(&semc,0,0);

    pthread_t id1, id2,id3;
    pthread_create(&id1,NULL,funa,NULL);
    pthread_create(&id2,NULL,funb,NULL);
    pthread_create(&id3,NULL,func,NULL);

    pthread_join(id1,NULL);
    pthread_join(id2,NULL);
    pthread_join(id3,NULL);

    sem_destroy(&sema);
    sem_destroy(&semb);
    sem_destroy(&semc);

    exit(0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值