• linux C 总结篇(线程)下


    线程同步

    1.互斥锁

    同一个时刻只允许一个线程执行一段关键代码,防止发生读写错乱。

    锁的初始化(使用互斥锁之前必须先初始化)

    1.将宏(PTHREAD_MUTEX_INITIALIZER)赋给锁(pthread_mutex_t mlock)

    2.使用 pthread_mutex_init 函数

         int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
    

    参数restrict attr表示互斥锁的属性,NULL 为默认属性 。

    加锁与解锁

       #include <pthread.h>
       int pthread_mutex_lock(pthread_mutex_t *mutex);
       int pthread_mutex_trylock(pthread_mutex_t *mutex);
       int pthread_mutex_unlock(pthread_mutex_t *mutex);
    

    说明:1.加锁时,如果锁已经被加了,加锁线程就会阻塞等待,直到解锁

    2.pthread_mutex_lock 返回说明加锁成功 ,不返回说明阻塞等待 。pthread_mutex_trylock返回0说明没有加锁,返回其他值说明已经被加锁(类比于文件锁F_GETLK)

       int pthread_mutex_unlock(pthread_mutex_t *mutex);
    

    解锁时需要满足的条件:1.互斥锁处于加锁的状态

    2.加锁的线程必须是给他上锁的线程。(一句话:解铃还需系铃人!!

    锁的清除

     int pthread_mutex_destroy(pthread_mutex_t *mutex); //释放互斥锁占用的资源
    

    必须保证锁被解开,否则返回EBUSY 。成功返回0

    具体实现过程介绍:一个线程等待条件变量被设置为真,另一个线程在使用完资源后设置条件为真 。互斥锁保护条件变量

    1.条件变量的初始化

    1.将宏(PTHREAD_COND_INITIALIZER)赋给条件变量(pthread_cond_t mcond)

    2.使用 pthread_cond_init 函数

       int pthread_cond_init(pthread_cond_t *restrict cond,
              const pthread_condattr_t *restrict attr);
    

    参数restrict attr表示互斥锁的属性,%99 的情况下用的是NULL

    2.等待条件变量成立

         int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);
         int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
    

    说明:pthread_cond_wait 释放互斥锁,等待条件变量被设置为真,pthread_cond_timedwait 规定了等待时间time.越时返回ETIMEOUT ,结束等待。

    3.激活条件变量

      #include <pthread.h>
       int pthread_cond_broadcast(pthread_cond_t *cond);
       int pthread_cond_signal(pthread_cond_t *cond);
    

    说明:pthread_cond_signal 激活一个等待条件变量为真的线程。 pthread_cond_broadcast 激活所有等待线程

    4.清除条件变量

       int pthread_cond_destroy(pthread_cond_t *cond);
    

    说明:没有线程等待该条件变量成立时清除,否则返回EBUSY

    小示例:

    #include<stdio.h>
    #include<unistd.h>
    #include<pthread.h>
    pthread_mutex_t mutex ;//互斥锁
    pthread_cond_t cond ;//条件变量
    void *thread1( void *arg )
    {
        pthread_cleanup_push(pthread_mutex_unlock ,&mutex); //退出时会执行它,用以清除资源(它又会指向一个函数:pthread_mutex_t_unlock)
        while(1)
        {
            printf("thread1 is running !! 
    ");
            pthread_mutex_lock(&mutex);     //防止多个线程同时请求pthread_cond_wait() 
            pthread_cond_wait(&cond ,&mutex); //阻塞等待条件变量被设置为1
            printf("thread 1 is apply the conditionn !! 
    ");
            pthread_mutex_unlock(&mutex);
            sleep(1);
        }
        pthread_cleanup_pop(0);
    }
    void *thread2( void *arg )
    {
        while(1)
        {
            printf("thread2 is running !! 
    ");
            pthread_mutex_lock(&mutex);
            pthread_cond_wait(&cond ,&mutex); //阻塞等待条件变量被设置为1
            printf("thread2 is apply the conditionn !! 
    ");
            pthread_mutex_unlock(&mutex);
            sleep(1);
        }
    }
    int main(void)
    {
        pthread_t tid1 ,tid2 ;
        printf("520520505201505205020502220500
    ");
        pthread_mutex_init(&mutex,NULL);
        pthread_cond_init(&cond,NULL);
        pthread_create(&tid1 ,NULL,(void *)thread1 ,NULL);
        pthread_create(&tid2 ,NULL,(void *)thread2 ,NULL);
        do
        {
            pthread_cond_signal(&cond); //循环设置条件变量为1
        }while(1);
        sleep(50);
        pthread_exit(0);
    }
    

    执行结果:

    这里写图片描述

    说明:两个线程被启动,等待同一个条件变量,main 函数中循环激活条件变量,使得两个线程同步运行

    3.异步信号

    信号与任何线程异步,也就是说信号到达线程的时间是不定的。如果有多个线程可以接受信号,则只有一个被选中。如果有许多的信号被传送,则分配给每一个线程处理,不会重复。如果所有的线程都屏蔽该信号,信号就会挂起,直到有信号解除屏蔽。

      #include <signal.h>
      int pthread_kill(pthread_t thread, int sig);
      int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
      int sigwait(const sigset_t *set, int *sig);
    

    说明:pthread_kill 向特定的线程发送信号。pthread_sigmask设置线程信号屏蔽码,但对不允许屏蔽的Cancel和不允许响应的Restart 进行了保护。sigwait阻塞线程,等待set 中指定的信号之一到达 ,存放在sig 中

    出错处理

    头文件errno.h 中定义了变量errno 存储了错误发生时的错误码 ,程序刚开始时为0(其实errno相当于全局变量了)

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<sys/types.h>
    #include<errno.h>
    #include<string.h>
    FILE* open_file(char *filename)
    {
        FILE *stream ;
        errno = 0;
        stream=fopen(filename ,"rw+");
        if(!stream)
        {
            printf("can not open the %s : error == %d 
    ",filename ,errno);
            exit(-1);
        }
        else return stream ;
    }
    int main(void)
    {
        char *filename="test";
        open_file(filename);
        return 0;
    }
    

    执行结果:

    这里写图片描述

    错误码

    常用错误码查询

    #ifndef _I386_ERRNO_H
    #define _I386_ERRNO_H
    #define EPERM 1 / *不允许操作* /
    #define ENOENT 2 / *没有这样的文件或目录* /
    #define ESRCH 3 / *没有这样的过程* /
    #define EINTR 4 / *中断的系统调用* /
    #define EIO 5 / * I / O错误* /
    #define ENXIO 6 / *没有这样的设备或地址* /
    #define E2BIG 7 / * Arg列表太长* /
    #define ENOEXEC 8 / * Exec格式错误* /
    #define EBADF 9 / *不良文件号* /
    #define ECHILD 10 / *没有子进程* /
    #define EAGAIN 11 / *再试一次* /
    #define ENOMEM 12 / *内存不足* /
    #define EACCES 13 / *权限被拒绝* /
    #define EFAULT 14 / *错误地址* /
    #define ENOTBLK 15 / *阻止设备* /
    #define EBUSY 16 / *设备或资源繁忙* /
    #define EEXIST 17 / *文件存在* /
    #define EXDEV 18 / *跨设备链接* /
    #define ENODEV 19 / *没有这样的设备* /
    #define ENOTDIR 20 / *不是目录* /
    #define EISDIR 21 / *是一个目录* /
    #define EINVAL 22 / *参数无效* /
    #define ENFILE 23 / *文件表溢出* /
    #define EMFILE 24 / *打开的文件太多* /
    #define ENOTTY 25 / *不是打字机* /
    #define ETXTBSY 26 / *文本文件忙* /
    #define EFBIG 27 / *文件太大* /
    #define ENOSPC 28 / *设备上没有剩余空间* /
    #define ESPIPE 29 / *非法寻求* /
    #define EROFS 30 / *只读文件系统* /
    #define EMLINK 31 / *链接太多* /
    #define EPIPE 32 / *破碎管* /
    #define EDOM 33 / *从func * /
    #define ERANGE 34 / *数学结果不可代表* /
    #define EDEADLK 35 / *资源死锁将发生* /
    #define ENAMETOOLONG 36 / *文件名太长* /
    #define ENOLCK 37 / *无记录锁* /
    #define ENOSYS 38 / *功能未实现* /
    #define ENOTEMPTY 39 / *目录不为空* /
    #define ELOOP 40 / *遇到太多的符号链接* /
    #define EWOULDBLOCK EAGAIN / *操作将阻止* /
    #define ENOMSG 42 / *没有所需类型的消息* /
    #define EIDRM 43 / *标识符已删除* /
    #define ECHRNG 44 / *频道号超出范围* /
    #define EL2NSYNC 45 / * 2级不同步* /
    #define EL3HLT 46 / * 3级停止* /
    #define EL3RST 47 / * 3级复位* /
    #define ELNRNG 48 / *链接号超出范围* /
    #define EUNATCH 49 / *协议驱动程序未附加* /
    #define ENOCSI 50 / *无CSI结构* /
    #define EL2HLT 51 / * 2级暂停* /
    #define EBADE 52 / *无效交换* /
    #define EBADR 53 / *无效的请求描述符* /
    #define EXFULL 54 / * Exchange full * /
    #define ENOANO 55 / *无阳极* /
    #define EBADRQC 56 / *请求代码无效* /
    #define EBADSLT 57 / *无效插槽* /
    #define EDEADLOCK EDEADLK
    #define EBFONT 59 / *坏字体文件格式* /
    #define ENOSTR 60 / *设备不是流* /
    #define ENODATA 61 / *无数据资料* /
    #define ETIME 62 / *计时器已过期* /
    #define ENOSR 63 / *从流资源* /
    #define ENONET 64 / *机器不在网络上* /
    #define ENOPKG 65 / *软件包未安装* /
    #define EREMOTE 66 / * Object is remote * /
    #define ENOLINK 67 / * Link已被切断* /
    #define EADV 68 / *广告错误* /
    #define ESRMNT 69 / * Srmount错误* /
    #define ECOMM 70 / *发送通信错误* /
    #define EPROTO 71 / *协议错误* /
    #define EMULTIHOP 72 / * Multihop尝试* /
    #define EDOTDOT 73 / * RFS具体错误* /
    #define EBADMSG 74 / *不是数据信息* /
    #define EOVERFLOW 75 / *值对于定义的数据类型来说太大* /
    #define ENOTUNIQ 76 / *网络名称不唯一* /
    #define EBADFD 77 / *文件描述符处于坏状态* /
    #define EREMCHG 78 / *远程地址更改* /
    #define ELIBACC 79 / *无法访问所需的共享库* /
    #define ELIBBAD 80 / *访问损坏的共享库* /
    #define ELIBSCN 81 / * .lib部分在a.out损坏* /
    #define ELIBMAX 82 / *尝试链接到太多的共享库* /
    #define ELIBEXEC 83 / *无法直接执行共享库* /
    #define EILSEQ 84 / *非法字节序列* /
    #define ERESTART 85 / *中断的系统调用应重新启动* /
    #define ESTRPIPE 86 / *流管道错误* /
    #define EUSERS 87 / *用户太多* /
    #define ENOTSOCK 88 / *套接字操作在非socket * /
    #define EDESTADDRREQ 89 / *需要目的地址* /
    #define EMSGSIZE 90 / *留言太久* /
    #define EPROTOTYPE 91 / *协议错误类型为套接字* /
    #define ENOPROTOOPT 92 / *协议不可用* /
    #define EPROTONOSUPPORT 93 / *不支持协议* /
    #define ESOCKTNOSUPPORT 94 / *不支持套接字* /
    #define EOPNOTSUPP 95 / *传输端点不支持的操作* /
    #define EPFNOSUPPORT 96 / *不支持协议族*
    #define EAFNOSUPPORT 97 / *协议不支持的地址族*
    #define EADDRINUSE 98 / *地址已在使用* /
    #define EADDRNOTAVAIL 99 / *无法分配请求的地址* /
    #define ENETDOWN 100 / *网络已关闭* /
    #define ENETUNREACH 101 / *网络无法访问* /
    #define ENETRESET 102 / *网络由于重置而丢弃连接* /
    #define ECONNABORTED 103 / *软件导致连接中止* /
    #define ECONNRESET 104 / *由对等体重新连接*/
    

    提示错误信息

      #include<stdio.h>
      void perror(const char *s);
      #include<string.h>
      char *strerror(int errnum);
    

    说明: 1. strerror 根据参数errnum获得描述错误信息的字符串 . 2. perror 打印错误信息到stderr ,如果为空,打印错误信息,如果不为空,先打印参数s ,然后添加冒号和空格 ,最后是错误信息

  • 相关阅读:
    汉字转拼音
    多数组求笛卡尔积
    curl post参数,接口接收不到数据问题
    判断IMEI或MEID是否合法
    javascript 可控速度的上下拉菜单
    去掉android点击事件产生的半透明蓝色背景
    go.js是什么
    jQuery效果——动画
    jQuery选择器
    vue全局组件局部组件的使用
  • 原文地址:https://www.cnblogs.com/Tattoo-Welkin/p/10335338.html
Copyright © 2020-2023  润新知