嵌入式入门day8

1.信号初始化:

  • #include <semaphore.h>
    sem_init(&sem[0],int pshared,unsigned int value);

-pshared:
0:给线程使用
!0:可以给进程使用
-value:初始化值
2.p操作
(a)函数原型

  • #include <semaphore.h>
    int sem_wait(sem_t *sem);//阻塞p操作

功能:阻塞p操作集合中某个信号量,值-1
如果能够p操作成功最好,否则就阻塞直到p操作操作成功为止。

返回值:成功返回0,失败返回-1,errno被设置。

参数:p操作的某个信号量。
比如:sem_wait(&sem[0]);

sem_wait的兄弟函数:

  • int sem_trywait(sem_t *sem):不阻塞
    如果能够p操作就p操作,如果不能p操作就出错返回,不会阻塞。
  • int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
    可以设置阻塞时间,如果能够p操作就p操作,不能就阻塞,如果在设置的时间内好没有p操作成功就是出错返回,不再阻塞。
    3.v操作
    (a)函数原型
  • #include <semaphore.h>
    int sem_post(sem_t *sem);

功能:对某个信号量进行v操作,v操作不存在阻塞问题。v操作成功后,信号量的值会+1

返回值:成功返回0,失败返回-1,errno被设置。(b)代码演示
sem_post(&sem[0]);
4. 初始化条件变量
函数原型:

  • #include <pthread.h>
    int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);

功能:初始化条件变量,与互斥锁的初始化类似。

  • pthread_cond_t cond; //定义条件变量
    pthread_cond_init(&cond, NULL); //第二个参数为NULL,表示不设置条件变量的属性。
    也可以直接初始化:
    pthread_cond_t cond =PTHREAD_COND_INITIALIZER;//与互斥锁的初始化的原理是一样的

返回值:成功返回0,失败返回非零错误号

参数:
- cond:条件变量
- attr:用于设置条件变量的属性,设置为NULL,表示使用默认属性
5.进程 VS 线程:
(1)多线程比多进程成本低,但性能更低 :
多进程是立体交通系统,虽然造价高,上坡下坡多耗点油,但是不堵车。
多线程是平面交通系统,造价低,但红绿灯太多,老堵车。
(2) 区别
-进程是资源分配的最小单位,线程是任务调度的最小单位;
-每个进程拥有独立的地址空间,多个线程共享进程地址空间:

  • 线程之间切换比进程之间切换开销少;线程的调度必须通过频繁加锁来保持同步,影响了线程并发性能;
  • 进程比线程更健壮,多进程之间相互独立,进程的异常对其他进程无影响,一个线程的崩溃可能影响其他线程或者整个程序;
  • 线程之间的通信更方便(小数据量),同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点;
  • 多线程的代码结构比多进程代码结构易读;

(3)如何选择?

  • 需要频繁创建销毁的优先用线程
  • 高性能交易服务器中间件,如TUXEDO,都是主张多进程的
  • 需要进行大量计算的优先使用线程
  • 强相关的处理用线程,弱相关的处理用进程
  • 多机分布的用进程,多核分布的用线程
    示例代码:
周璇 20:57:19
 1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <pthread.h>
  5 #include <string.h>
  6 #include <errno.h>
  7 #include <sys/types.h>
  8 #include <sys/stat.h>
  9 #include <fcntl.h>
 10 #include <signal.h>
 11 
 12 
 13 #define SECON_PTH_NUMS  2  //次线程数量
 14 #define PTHEXIT         -1      
 15 
 16 
 17 /* 传递给线程的参数 */
 18 typedef struct pthread_arg
 19 {
 20         pthread_t tid;//存放线程tid
 21         int pthno;//我自己定义的编号
 22         int fd;//文件描述符
 23 }ptharg;
 24 
 25 
 26 
 27 struct gloable_va
 28 {
 29         ptharg pth_arg[SECON_PTH_NUMS];//结构体数组,每个元素会被当做参数传递给对应的次线程
 30         int pth_exit_flg[SECON_PTH_NUMS];//每个元素存放对应编号线程的退出状态
 31         pthread_attr_t attr;//存放线程新属性
 32 }glbva;
 33 
 34 void print_err(char *str, int line, int err_no)
 35 {
 36         printf("%d, %s:%s", line, str, strerror(err_no));
 37         exit(-1);
 38 }
 39 
 40 /* 线程退出处理函数 */
 41 void pth_exit_deal(void *arg)
 42 {
 43         pthread_t tid = ((ptharg *)arg)->tid;
 44 
 45         printf("!!! pthread %lu exit\n", tid);
 46 }
 47 
 48 void *pth_fun(void *pth_arg)
 49 {
 50         int fd = ((ptharg *)pth_arg)->fd;
 51         int pthno = ((ptharg *)pth_arg)->pthno;
 52         pthread_t tid = ((ptharg *)pth_arg)->tid;
 53 
 54         //pthread_detach(pthread_self());//线程把自己分离出去
 55 
 56         //注册线程退出处理函数
 57         pthread_cleanup_push(pth_exit_deal, pth_arg);
 58 
 59         printf("pthno=%d, pthread_id=%lu\n", pthno, tid);
 60 
 61         while(1)
 62         {
 63                 write(fd, "hello ", 6);
 64                 write(fd, "world\n", 6);
 65                 //检测退出状态
 66                 if(glbva.pth_exit_flg[pthno] == PTHEXIT) break;
 67         }
 68 
 69 
 70         pthread_cleanup_pop(!0);
 71         return NULL;
 72         pthread_exit((void *)10);
 73 }
 74 
75 void signal_fun(int signo)
 76 {
 77         if(SIGALRM == signo)
 78         {
 79                 int i = 0;
 80                 for(i=0; i<SECON_PTH_NUMS; i++)
 81                 {
 82                         //pthread_cancel(glbva.pth_arg[i].tid);//取消次线程
 83                         glbva.pth_exit_flg[i] = PTHEXIT;//设置为退出状态
 84                 }
 85         }
 86         else if(SIGINT == signo)
 87         {
 88                 exit(0);
 89         }
 90 }
 91 
 92 void process_exit_deal(void)
 93 {
 94         /* 销毁线程的属性设置 */
 95         int ret = 0;
 96         ret = pthread_attr_destroy(&glbva.attr);
 97         if(ret != 0) print_err("pthread_attr_destroy fail", __LINE__, ret);
 98 
 99         printf("\nprocess exit\n");
100 }
101
102 int main(void)
103 {
104         int fd = 0;
105         int i = 0;
106         int ret = 0;
107 
108         //注册进程退出处理函数,exit正常终止进程时弹栈调用
109         atexit(process_exit_deal);
110 
111         //打开文件,供线程操作,所有的线程(函数)可以共享打开的文件描述符
112         fd = open("./file", O_RDWR|O_CREAT|O_TRUNC, 0664);
113         if(fd == -1) print_err("open ./file fail", __LINE__, errno);
114 
115         /* 初始化护attr, 设置一些基本的初始值 */
116         ret = pthread_attr_init(&glbva.attr);
117         if(ret != 0) print_err("pthread_attr_init fail", __LINE__, ret);
118 
119         /* 设置分离属性 */
120         ret = pthread_attr_setdetachstate(&glbva.attr, PTHREAD_CREATE_DETACHED);
121         if(ret != 0) print_err("pthread_attr_setdetachstate fail", __LINE__, ret);
122 
123         /* 通过循环创建两个次线程 */
124         for(i=0; i<SECON_PTH_NUMS; i++)
125         {
126                 glbva.pth_arg[i].fd = fd;//保存文件描述符
127                 glbva.pth_arg[i].pthno = i; //我自己给的线程编号
128                                                            //创建好次线程后,讲次线程分离
129                 ret = pthread_create(&glbva.pth_arg[i].tid, &glbva.attr, pth_fun, (void *)&glbva.pth_arg[i]);
130                 if(ret != 0) print_err("pthread_create fail", __LINE__, ret);
131         }
132 
133         printf("main tid = %lu\n", pthread_self());
134 
135         signal(SIGINT, signal_fun);
136 
137         /* 定时5秒,时间到后取消次线程 */
138         signal(SIGALRM, signal_fun);
139         alarm(3);
140 
141         #if 0
142         void *retval = NULL;
143         for(i=0; i<SECON_PTH_NUMS; i++)
144         {
145                 //阻塞等待此线程结束,回收次线程资源,并通过第二个参数接受返回值
146                 pthread_join(glbva.pth_arg[i].tid, &retval);
147                 printf("@@ %ld\n", (long)retval);
148         }
149         #endif
150 
151 
152         while(1)
153         {
154                 write(fd, "hello ", 6);
155                 write(fd, "world\n", 6);
156         }
157 
158         return 0;
159 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值