Linux学习第十一天

这篇博客回顾了Linux学习的第十一课,重点讲解了信号处理(如使用sigaction实现重入)和线程相关概念。内容包括线程创建、清理、同步与互斥,涉及互斥锁的初始化、加锁、解锁操作,以及线程锁在进程间共享和错误检查的应用。还探讨了条件变量在多线程等待与激发中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、昨日回顾

1、信号处理sigaction

2、使用sigaction如何实现不断重入效果?

 struct sigaction act;

 act.sa_flags=SA_SIGINFO|SA_NODEFER;

3、想在2号信号的处理流程过程中,屏蔽3号信号

 struct sigaction act;

 act.sa_flags=SIGINFO;

 act.sa_sigaction=sig_Func;

 

 sigemptyset(&act.sa_mask);

 sigaddset(&act.sa_mask,SIGQUIT);

4、如何设置信号屏蔽?

 sigset_t mask;

 sigemptyset(&mask);

 sigaddset(&mask,SIGQUIT);//设置屏蔽信号

 sigprocmask(SIG_BLOCK,&mask,NULL);//增加屏蔽

 sleep(3);

 sigpromask(SIG_UNBLOCK,&mask,NULL);//解除屏蔽

5、线程pthread

(1)线程创建pthread_create(&pthid,NULL,thread_Func,NULL);

(2)线程退出pthread_exit((void)*2)

(3)线程合并

 long threadRet;

 pthread_join(pthid,(void**)&threadPRet);

 

 

二、上午内容

1、线程清理

(1)查看清理函数的执行顺序

①代码示例pthread_cleanup_exec.c(已完成)

 

#include"func.h"

void cleanup(void*p)

{

    printf("I am cleanup %ld\n",(long)p);

 

}

 

void *thread_Func(void *p)

{

    pthread_cleanup_push(cleanup,(void*)1);

    pthread_cleanup_push(cleanup,(void*)2);

    pthread_exit(NULL);

    pthread_cleanup_pop(1);

    pthread_cleanup_pop(2);

 

}

int main(int argc, char* argv[])

{

    pthread_t pthid;

    int ret=pthread_create(&pthid,NULL,thread_Func,NULL);

 

    long threadRet;

    ret=pthread_join(pthid,(void **)&threadRet);

    THREAD_ERROR_CHECK(ret,"pthread_join");

 

    printf("threadRet=%ld",threadRet);

    return 0;

}

 

 

Ⅰ先压栈的清理函数后执行

Ⅱ该功能使用的是清理栈

 

②工作的时候如何写清理资源?

代码示例pthread_cleanup_malloc.c(已完成)

 

#include"func.h"

void cleanup(void*p)

{

    free(p);

    printf("I am cleanup\n");

 

}

 

void *thread_Func(void *p)

{

    p=malloc(20);

    pthread_cleanup_push(cleanup,p);

    sleep(1);

    pthread_cleanup_pop(1);

    pthread_exit(NULL);

 

}

int main(int argc, char* argv[])

{

    pthread_t pthid;

    int ret=pthread_create(&pthid,NULL,thread_Func,NULL);

 

    long threadRet;

    ret=pthread_join(pthid,(void **)&threadRet);

    THREAD_ERROR_CHECK(ret,"pthread_join");

 

    printf("threadRet=%ld",threadRet);

    return 0;

}

 

2、线程的同步与互斥:双方互斥进行

(1)互斥锁

①锁的初始化

Ⅰ使用函数

pthread_mutex_t mutex;

pthread_mutex_init;

 

②加锁操作

Ⅰ使用函数pthread_mutex_lock();

Ⅱ代码示例pthread_add2000.c

 

#include <func.h>

#define N 20000000

typedef struct{

    int val;

    pthread_mutex_t mutex;

}Data_t;

void* threadFunc(void* p)

{

    int i;

    Data_t* threadInfo=(Data_t*)p;

    for(i=0;i<N;i++)

    {

        pthread_mutex_lock(&threadInfo->mutex);

        threadInfo->val+=1;

        pthread_mutex_unlock(&threadInfo->mutex);

    }

}

int main(int argc,char* argv[])

{

    pthread_t pthid;

    int ret;

    Data_t threadInfo;

    threadInfo.val=0;

    ret=pthread_mutex_init(&threadInfo.mutex,NULL);

    THREAD_ERROR_CHECK(ret,"pthread_mutex_init");

    struct timeval start,end;

    gettimeofday(&start,NULL);

    ret=pthread_create(&pthid,NULL,threadFunc,&threadInfo);

    THREAD_ERROR_CHECK(ret,"pthread_create");

    int i;

    for(i=0;i<N;i++)

    {

        pthread_mutex_lock(&threadInfo.mutex);

        threadInfo.val+=1;

        pthread_mutex_unlock(&threadInfo.mutex);

    }

    pthread_join(pthid,NULL);//等待子线程

    gettimeofday(&end,NULL);

    printf("I am main thread,val=%d,use time=%ld\n",threadInfo.val,(end.tv_sec-start.tv_sec)*1000000+end.tv_usec-start.tv_usec);

    return 0;

}

 

 

③解锁操作

Ⅰ代码例子pthread_mutex_trylock.c

 

#include <func.h>

typedef struct{

    pthread_mutex_t mutex;

}Data_t;

void* threadFunc(void* p)

{

    Data_t* pArg=(Data_t*)p;

    int ret=pthread_mutex_trylock(&pArg->mutex);

    CHILD_THREAD_ERROR_CHECK(ret,"pthread_mutex_trylock");

    printf("child lock success\n");

    pthread_exit(NULL);

}

int main(int argc,char* argv[])

{

    Data_t threadInfo;

    pthread_t pthid;

    pthread_mutex_init(&threadInfo.mutex,NULL);

    pthread_create(&pthid,NULL,threadFunc,&threadInfo);

    pthread_mutex_lock(&threadInfo.mutex);

    printf("main thread lock success\n");

    int ret=pthread_join(pthid,NULL);

    THREAD_ERROR_CHECK(ret,"pthread_join");

    return 0;

}

 

 

④测试加锁

Ⅰ代码示例sem_add1000.c

 

#include <func.h>

#define N 20000000

int main(int argc,char* argv[])

{

    int semArrId=semget(1000,1,IPC_CREAT|0600);

    ERROR_CHECK(semArrId,-1,"semget");                                                                                   

    int shmid;

    shmid=shmget(1000,1<<20,IPC_CREAT|0600);

    ERROR_CHECK(shmid,-1,"shmget");

    int *p;

    p=(int*)shmat(shmid,NULL,0);

    ERROR_CHECK(p,(int*)-1,"shmat");

    *p=0;

    int ret=semctl(semArrId,0,SETVAL,1);

    ERROR_CHECK(ret,-1,"semctl");

    struct sembuf sopp,sopv;

    sopp.sem_num=0;

    sopp.sem_op=-1;

    sopp.sem_flg=SEM_UNDO;

    sopv.sem_num=0;

    sopv.sem_op=1;

    sopv.sem_flg=SEM_UNDO;

    struct timeval start,end;

    gettimeofday(&start,NULL);

    if(!fork())

    {

        int i;

        for(i=0;i<N;i++)

        {

            //加锁

            semop(semArrId,&sopp,1);

            p[0]=p[0]+1;

            semop(semArrId,&sopv,1);

            //解锁

        }

    }else{

        int i;

        for(i=0;i<N;i++)

        {

            semop(semArrId,&sopp,1);

            p[0]=p[0]+1;

            semop(semArrId,&sopv,1);

        }

        wait(NULL);

        gettimeofday(&end,NULL);

        printf("result=%d,use time=%ld\n",p[0],(end.tv_sec-start.tv_sec)*1000000+end.tv_usec-start.tv_usec);

    }

    return 0;

}

 

 

 

(2)别人加的锁,可以解开吗?

Ⅰ代码例子pthread_mutex_trylock.c

 

#include <func.h>

typedef struct{

    pthread_mutex_t mutex;

}Data_t;

void* threadFunc(void* p)

{

    Data_t* pArg=(Data_t*)p;

    int ret=pthread_mutex_trylock(&pArg->mutex);

    CHILD_THREAD_ERROR_CHECK(ret,"pthread_mutex_trylock");

    printf("child lock success\n");

    pthread_exit(NULL);

}

int main(int argc,char* argv[])

{

    Data_t threadInfo;

    pthread_t pthid;

    pthread_mutex_init(&threadInfo.mutex,NULL);

    pthread_create(&pthid,NULL,threadFunc,&threadInfo);

    pthread_mutex_lock(&threadInfo.mutex);

    printf("main thread lock success\n");

    int ret=pthread_join(pthid,NULL);

    THREAD_ERROR_CHECK(ret,"pthread_join");

    return 0;

}

 

 

Ⅱ代码例子pthread_mutex_unlock_other.c

 

#include <func.h>

typedef struct{

    pthread_mutex_t mutex;

}Data_t;

void* threadFunc(void* p)

{

    Data_t* pArg=(Data_t*)p;

    pthread_mutex_unlock(&pArg->mutex);

    pthread_mutex_lock(&pArg->mutex);

    printf("child lock success\n");

    pthread_exit(NULL);

}

int main(int argc,char* argv[])

{

    Data_t threadInfo;

    pthread_t pthid;

    pthread_mutex_init(&threadInfo.mutex,NULL);

    pthread_create(&pthid,NULL,threadFunc,&threadInfo);

    pthread_mutex_lock(&threadInfo.mutex);

    printf("main thread lock success\n");

    int ret=pthread_join(pthid,NULL);

    THREAD_ERROR_CHECK(ret,"pthread_join");

    return 0;

}

 

 

锁传递,应该传递地址

 

 

3、使用线程锁统计时间

 

三、下午的内容

1、如何加锁?

①加两次锁

使用命令pthread_mutex_lock

代码例子pthread_mutex_locktwice.c(已完成)

给锁加两次锁

#include"func.h"

 

int main(int argc,char* argv[])

{

    pthread_mutex_t mutex;//定义锁

    pthread_mutexattr_t mattr;//定义互斥锁属性

   

    int ret;//定义返回值

    ret=pthread_mutexattr_init(&mattr);//初始化互斥锁属性

    THREAD_ERROR_CHECK(ret,"pthread_mutexattr_init");//错误检查

 

    pthread_mutexattr_settype(&mattr,PTHREAD_MUTEX_RECURSIVE);//设置互斥锁属性类型

    pthread_mutex_init(&mutex,&mattr);//初始化互斥锁

    pthread_mutex_lock(&mutex);//第一次加锁

    ret=pthread_mutex_lock(&mutex);//第二次加锁,得到返回值

    THREAD_ERROR_CHECK(ret,"pthread_mutex_lock");//错误检查

    printf("you can see me\n");//打印输出

    return 0;

 

}

 

 

②如何检测是否有错误

代码示例thread_mutex_errorcheck.c

避免对同一把锁加锁两次

 

#include <func.h>

 

int main(int argc,char* argv[])

{

    pthread_mutex_t mutex;

    pthread_mutexattr_t mattr;

    int ret;

    ret=pthread_mutexattr_init(&mattr);

    THREAD_ERROR_CHECK(ret,"pthread_mutexattr_init");

    pthread_mutexattr_settype(&mattr,PTHREAD_MUTEX_ERRORCHECK);//允许同一个线程对同一把锁加锁多次

    pthread_mutex_init(&mutex,&mattr);

    pthread_mutex_lock(&mutex);

    ret=pthread_mutex_lock(&mutex);

    THREAD_ERROR_CHECK(ret,"pthread_mutex_lock");

    printf("you can see me\n");

    return 0;

}

 

 

③使用进程锁进行2000万加法。

代码示例fork_mutex.c

 

#include <func.h>

#define N 20000000

typedef struct{

    int val;

    pthread_mutex_t mutex;

}Data_t,*pData_t;

int main(int argc,char* argv[])

{

    int semArrId=semget(1000,1,IPC_CREAT|0600);

    ERROR_CHECK(semArrId,-1,"semget");                                                                                   

    int shmid;

    shmid=shmget(1000,1<<20,IPC_CREAT|0600);

    ERROR_CHECK(shmid,-1,"shmget");

    pData_t p;

    p=(pData_t)shmat(shmid,NULL,0);

    ERROR_CHECK(p,(pData_t)-1,"shmat");

    p->val=0;

    pthread_mutexattr_t mattr;

    pthread_mutexattr_init(&mattr);

    pthread_mutexattr_setpshared(&mattr,PTHREAD_PROCESS_SHARED);//设置为进程共享

    int ret=pthread_mutex_init(&p->mutex,&mattr);

    THREAD_ERROR_CHECK(ret,"pthread_mutex_init");

    struct timeval start,end;

    gettimeofday(&start,NULL);

    if(!fork())

    {

        int i;

        for(i=0;i<N;i++)

        {

            //加锁

            pthread_mutex_lock(&p->mutex);

            p->val+=1;

            pthread_mutex_unlock(&p->mutex);

            //解锁

        }

    }else{

        int i;

        for(i=0;i<N;i++)

        {

            pthread_mutex_lock(&p->mutex);

            p->val+=1;

            pthread_mutex_unlock(&p->mutex);

        }

        wait(NULL);

        gettimeofday(&end,NULL);

        printf("result=%d,use time=%ld\n",p->val,(end.tv_sec-start.tv_sec)*1000000+end.tv_usec-start.tv_usec);

    }

    return 0;

}

 

 

tips:

Ⅰ锁使用的区域是在共享内存内

Ⅱ在加锁代码中,先加锁,在执行操作,之后再解锁

 

④代码示例sale_tickets.c

 

#include <func.h>

typedef struct{

    int tickets;

    pthread_mutex_t mutex;

}Data_t;

void cleanup(void *p)

{

    pthread_mutex_unlock((pthread_mutex_t*)p);

    printf("unlock success\n");

}

 

void* saleWindows1(void* p)

{

    Data_t* pArg=(Data_t*)p;

    int i=0;

    while(1)

    {

        pthread_mutex_lock(&pArg->mutex);

        if(pArg->tickets>0)

        {

            //printf("I am saleWindows1 start sale,%d\n",pArg->tickets);

            pArg->tickets--;

            i++;

            //printf("I am saleWindows1 sale finish,%d\n",pArg->tickets);

            pthread_mutex_unlock(&pArg->mutex);

        }else{

            pthread_mutex_unlock(&pArg->mutex);

            printf("I am saleWindows1,%d\n",i);

            break;

        }

    }

    return NULL;

}

void* saleWindows2(void* p)

{

    Data_t* pArg=(Data_t*)p;

    int i=0;

    while(1)

    {

        pthread_mutex_lock(&pArg->mutex);

        if(pArg->tickets>0)

        {

            //printf("I am saleWindows2 start sale,%d\n",pArg->tickets);

            pArg->tickets--;

            i++;

            //printf("I am saleWindows2 sale finish,%d\n",pArg->tickets);

            pthread_mutex_unlock(&pArg->mutex);

        }else{

            pthread_mutex_unlock(&pArg->mutex);

            printf("I am saleWindows2,%d\n",i);

            break;

        }

    }

    return NULL;

}

int main(int argc,char* argv[])

{

    Data_t threadInfo;

    threadInfo.tickets=20000000;

    pthread_t pthid,pthid1;

    pthread_mutex_init(&threadInfo.mutex,NULL);

    pthread_create(&pthid,NULL,saleWindows1,&threadInfo);

    pthread_create(&pthid1,NULL,saleWindows2,&threadInfo);

    int ret;

    long threadRet;

    ret=pthread_join(pthid1,(void**)&threadRet);

    THREAD_ERROR_CHECK(ret,"pthread_join");

    ret=pthread_join(pthid,(void**)&threadRet);

    THREAD_ERROR_CHECK(ret,"pthread_join");

    printf("sale over\n");

    return 0;

}

 

tips:

Ⅰ在判断有没有票之前,就要加一个锁

 

 

2、条件变量

(1)两个线程要设置等待和激发

Ⅰ等待条件有两种方式:无条件等待和有条件等待

Ⅱ通过这种方式,就可以实现线程同步

 

!!要注意区别:进程间通信和进程间的同步

进程间的同步:可以通过管道、消息队列、或者信号量实现

①等待与激发

Ⅰ首先要初始化一个参数

代码示例:(子线程等待,主线程执行)

Pthread_cond.c

#include <func.h>

typedef struct{

    pthread_mutex_t mutex;

    pthread_cond_t cond;

}Data_t,*pData_t;

void* threadFunc(void* p)

{

    pData_t pArg=(pData_t)p;

    pthread_mutex_lock(&pArg->mutex);

    pthread_cond_wait(&pArg->cond,&pArg->mutex);

    pthread_mutex_unlock(&pArg->mutex);

    printf("I am child thread wake up\n");

    pthread_exit(NULL);

}

int main(int argc,char* argv[])

{

    Data_t threadInfo;

    pthread_mutex_init(&threadInfo.mutex,NULL);

    pthread_cond_init(&threadInfo.cond,NULL);

    pthread_t pthid;

    pthread_create(&pthid,NULL,threadFunc,&threadInfo);

    usleep(5000);

    pthread_cond_signal(&threadInfo.cond);//让条件变量成立

    pthread_join(pthid,NULL);

    printf("I am main thread\n");

    return 0;

}

 

 

②一个函数

上半部:

Ⅰ排队在对应的cond

Ⅱ解锁

Ⅲ睡觉

 

下半部

Ⅰ醒来

Ⅱ加锁

Ⅲ返回

 

 

Ⅰ条件变量初始化:pthread_cond_init

Ⅱ让条件变量成立pthread_cond_signal//让条件变量成立

 

tips:内核真正在调度的时候,调度单位是内核线程

 

④新的代码示例pthread_cond_twowait.c

 

#include <func.h>

typedef struct{

    pthread_mutex_t mutex;

    pthread_cond_t cond;

}Data_t,*pData_t;

void cleanup(void *p)

{

    pthread_mutex_unlock((pthread_mutex_t*)p);

    printf("unlock ok\n");

}

void* threadFunc(void* p)

{

    pData_t pArg=(pData_t)p;

    pthread_mutex_lock(&pArg->mutex);

    pthread_cleanup_push(cleanup,&pArg->mutex);

    pthread_cond_wait(&pArg->cond,&pArg->mutex);

    printf("wait return\n");

    pthread_cleanup_pop(1);

    printf("I am child thread wake up\n");

    pthread_exit(NULL);

}

#define N 2

int main(int argc,char* argv[])

{

    Data_t threadInfo;

    pthread_mutex_init(&threadInfo.mutex,NULL);

    pthread_cond_init(&threadInfo.cond,NULL);

    pthread_t pthid[N];

    int i;

    for(i=0;i<N;i++)

    {

        pthread_create(pthid+i,NULL,threadFunc,&threadInfo);

    }

    int ret;

    for(i=0;i<N;i++)

    {

        ret=pthread_cancel(pthid[i]);

        THREAD_ERROR_CHECK(ret,"pthread_cancel");

    }

    for(i=0;i<N;i++)

    {

        pthread_join(pthid[i],NULL);

    }

    printf("I am main thread\n");

    return 0;

}

 

 

tips:

Ⅰ多个线程在等待,代码示例是2个线程在等待

Ⅱ如何解决无法cancel线程的问题?使用cleanup,其中push放在wait前边,pop放在wait后边;要注意,要定义一个cleanup函数

 

⑤超时等待,代码示例

Pthread_cond_timedwait.c

 

#include <func.h>

typedef struct{

    pthread_mutex_t mutex;

    pthread_cond_t cond;

}Data_t,*pData_t;

void* threadFunc(void* p)

{

    pData_t pArg=(pData_t)p;

    struct timespec t;

    t.tv_sec=time(NULL)+3;

    t.tv_nsec=0;

    int ret;

    pthread_mutex_lock(&pArg->mutex);

    ret=pthread_cond_timedwait(&pArg->cond,&pArg->mutex,&t);

    pthread_mutex_unlock(&pArg->mutex);

    printf("I am child thread wake up,ret=%d\n",ret);

    pthread_exit(NULL);

}

int main(int argc,char* argv[])

{

    Data_t threadInfo;

    pthread_mutex_init(&threadInfo.mutex,NULL);

    pthread_cond_init(&threadInfo.cond,NULL);

    pthread_t pthid;

    pthread_create(&pthid,NULL,threadFunc,&threadInfo);

    sleep(1);

    pthread_cond_signal(&threadInfo.cond);

    pthread_join(pthid,NULL);

    printf("I am main thread\n");

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值