linux C 总结篇(线程)下

来源:互联网 发布:西安行知中学小升初 编辑:程序博客网 时间:2024/06/10 18:59

线程同步

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 !! \n");        pthread_mutex_lock(&mutex);     //防止多个线程同时请求pthread_cond_wait()         pthread_cond_wait(&cond ,&mutex); //阻塞等待条件变量被设置为1        printf("thread 1 is apply the conditionn !! \n");        pthread_mutex_unlock(&mutex);        sleep(1);    }    pthread_cleanup_pop(0);}void *thread2( void *arg ){    while(1)    {        printf("thread2 is running !! \n");        pthread_mutex_lock(&mutex);        pthread_cond_wait(&cond ,&mutex); //阻塞等待条件变量被设置为1        printf("thread2 is apply the conditionn !! \n");        pthread_mutex_unlock(&mutex);        sleep(1);    }}int main(void){    pthread_t tid1 ,tid2 ;    printf("520520505201505205020502220500\n");    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 \n",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 ,然后添加冒号和空格 ,最后是错误信息

原创粉丝点击