从0开始学FreeRTOS-(消息队列)-5
## 问题解答
曾经有人问我,FreeRTOS那么多API,到底怎么记住呢?
我想说,其实API不难记,就是有点难找,因为FreeRTOS的API很多都是带参宏,所以跳来跳去的比较麻烦,而且注释也很多,要找还真不是那么容易,不过也没啥,一般都会有API手册的,我就告诉大家一下:
**FreeRTOS Kernel: Reference Manual**
FreeRTOS内核:参考手册,大家可以在[官网下载](https://www.freertos.org/Documentation/RTOS_book.html),也能在后台得到。
当然书本是英文的,如果英语像我这样子不咋地的同学,可以用谷歌浏览器在官网直接看API手册,直接翻译一下就行了。传送门:[https://www.freertos.org/a00018.html](https://www.freertos.org/a00018.html)
![Reference Manual](https://img2018.cnblogs.com/blog/1834930/201910/1834930-20191015204300798-100318950.png)
![FreeRTOS官网的API](https://img2018.cnblogs.com/blog/1834930/201910/1834930-20191015204301380-1771154390.png)
## FreeRTOS消息队列
基于 FreeRTOS 的应用程序由一组独立的任务构成——每个任务都是具有独立权限的程序。这些独立的任务之间的通讯与同步一般都是基于操作系统提供的IPC通讯机制,而FreeRTOS 中所有的通信与同步机制都是基于队列实现的。
消息队列是一种常用于任务间通信的数据结构,队列可以在任务与任务间、中断和任务间传送信息,实现了任务接收来自其他任务或中断的不固定长度的消息。任务能够从队列里面读取消息,当队列中的消息是空时,挂起读取任务,用户还可以指定挂起的任务时间;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息,消息队列是一种异步的通信方式。
### 队列特性
#### 1.数据存储
队列可以保存有限个具有确定长度的数据单元。队列可以保存的最大单元数目被称为队列的“深度”。在队列创建时需要设定其深度和每个单元的大小。
通常情况下,队列被作为 FIFO(先进先出)缓冲区使用,即数据由队列尾写入,从队列首读出。当然,由队列首写入也是可能的。
往队列写入数据是通过字节拷贝把数据复制存储到队列中;从队列读出数据使得把队列中的数据拷贝删除。
#### 2.读阻塞
当某个任务试图读一个队列时,其可以指定一个阻塞超时时间。在这段时间中,如果队列为空,该任务将保持阻塞状态以等待队列数据有效。当其它任务或中断服务例程往其等待的队列中写入了数据,该任务将自动由阻塞态转移为就绪态。当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转移为就绪态。
由于队列可以被多个任务读取,所以对单个队列而言,也可能有多个任务处于阻塞状态以等待队列数据有效。这种情况下,一旦队列数据有效,只会有一个任务会被解除阻塞,这个任务就是所有等待任务中优先级最高的任务。而如果所有等待任务的优先级相同,那么被解除阻塞的任务将是等待最久的任务。
> 说些题外话,ucos中是具有广播消息的,当有多个任务阻塞在队列上,当发送消息的时候可以选择广播消息,那么这些阻塞的任务都能被解除阻塞。
#### 3.写阻塞
与读阻塞想反,任务也可以在写队列时指定一个阻塞超时时间。这个时间是当被写队列已满时,任务进入阻塞态以等待队列空间有效的最长时间。
由于队列可以被多个任务写入,所以对单个队列而言,也可能有多个任务处于阻塞状态以等待队列空间有效。这种情况下,一旦队列空间有效,只会有一个任务会被解除阻塞,这个任务就是所有等待任务中优先级最高的任务。而如果所有等待任务的优先级相同,那么被解除阻塞的任务将是等待最久的任务。
### 消息队列的工作流程
#### 1.发送消息
任务或者中断服务程序都可以给消息队列发送消息,当发送消息时,如果队列未满或者允许覆盖入队, FreeRTOS 会将消息拷贝到消息队列队尾,否则,会根据用户指定的阻塞超时时间进行阻塞,在这段时间中,如果队列一直不允许入队,该任务将保持阻塞状态以等待队列允许入队。当其它任务从其等待的队列中读取入了数据(队列未满),该任务将自动由阻塞态转为就绪态。当任务等待的时间超过了指定的阻塞时间,即使队列中还不允许入队,任务也会自动从阻塞态转移为就绪态,此时发送消息的任务或者中断程序会收到一个错误码 errQUEUE_FULL。
发送紧急消息的过程与发送消息几乎一样,唯一的不同是,当发送紧急消息时,发送的位置是消息队列队头而非队尾,这样,接收者就能够优先接收到紧急消息,从而及时进行消息处理。
下面是消息队列的发送API接口,函数中有FromISR则表明在中断中使用的。
![消息队列入队(发送)的API接口](https://img2018.cnblogs.com/blog/1834930/201910/1834930-20191015204301568-1378591799.png)
```
1 /*-----------------------------------------------------------*/
2 BaseType_t xQueueGenericSend( QueueHandle_t xQueue, (1)
3 const void * const pvItemToQueue, (2)
4 TickType_t xTicksToWait, (3)
5 const BaseType_t xCopyPosition ) (4)
6 {
7 BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired;
8 TimeOut_t xTimeOut;
9 Queue_t * const pxQueue = ( Queue_t * ) xQueue;
10
11 /* 已删除一些断言操作 */
12
13 for ( ;; ) {
14 taskENTER_CRITICAL(); (5)
15 {
16 /* 队列未满 */
17 if ( ( pxQueue->uxMessagesWaiting uxLength )
18 || ( xCopyPosition == queueOVERWRITE ) ) { (6)
19 traceQUEUE_SEND( pxQueue );
20 xYieldRequired =
21 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); (7)
22
23 /* 已删除使用队列集部分代码 */
24 /* 如果有任务在等待获取此消息队列 */
25 if ( listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive))==pdFALSE){ (8)
26 /* 将任务从阻塞中恢复 */
27 if ( xTaskRemoveFromEventList(
28 &( pxQueue->xTasksWaitingToReceive ) )!=pdFALSE) { (9)
29 /* 如果恢复的任务优先级比当前运行任务优先级还高,
30 那么需要进行一次任务切换 */
31 queueYIELD_IF_USING_PREEMPTION(); (10)
32 } else {
33 mtCOVERAGE_TEST_MARKER();
34 }
35 } else if ( xYieldRequired != pdFALSE ) {
36 /* 如果没有等待的任务,拷贝成功也需要任务切换 */
37 queueYIELD_IF_USING_PREEMPTION(); (11)
38 } else {
39 mtCOVERAGE_TEST_MARKER();
40 }
41
42 taskEXIT_CRITICAL(); (12)
43 return pdPASS;
44 }
45 /* 队列已满 */
46 else { (13)
47 if ( xTicksToWait == ( TickType_t ) 0 ) {
48 /* 如果用户不指定阻塞超时时间,退出 */
49 taskEXIT_CRITICAL(); (14)
50 traceQUEUE_SEND_FAILED( pxQueue );
51 return errQUEUE_FULL;
52 } else if ( xEntryTimeSet == pdFALSE ) {
53 /* 初始化阻塞超时结构体变量,初始化进入
54 阻塞的时间xTickCount和溢出次数xNumOfOverflows */
55 vTaskSetTimeOutState( &xTimeOut ); (15)
56 xEntryTimeSet = pdTRUE;
57 } else {
58 mtCOVERAGE_TEST_MARKER();
59 }
60 }
61 }
62 taskEXIT_CRITICAL(); (16)
63 /* 挂起调度器 */
64 vTaskSuspendAll();
65 /* 队列上锁 */
66 prvLockQueue( pxQueue );
67
68 /* 检查超时时间是否已经过去了 */
69 if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait)==pdFALSE){ (17)
70 /* 如果队列还是满的 */
71 if ( prvIsQueueFull( pxQueue ) != pdFALSE ) { (18)
72 traceBLOCKING_ON_QUEUE_SEND( pxQueue );
73 /* 将当前任务添加到队列的等待发送列表中
74 以及阻塞延时列表,延时时间为用户指定的超时时间xTicksToWait */
75 vTaskPlaceOnEventList(
76 &( pxQueue->xTasksWaitingToSend ), xTicksToWait );(19)
77 /* 队列解锁 */
78 prvUnlockQueue( pxQueue ); (20)
79
80 /* 恢复调度器 */
81 if ( xTaskResumeAll() == pdFALSE ) {
82 portYIELD_WITHIN_API();
83 }
84 } else {
85 /* 队列有空闲消息空间,允许入队 */
86 prvUnlockQueue( pxQueue ); (21)
87 ( void ) xTaskResumeAll();
88 }
89 } else {
90 /* 超时时间已过,退出 */
91 prvUnlockQueue( pxQueue ); (22)
92 ( void ) xTaskResumeAll();
93
94 traceQUEUE_SEND_FAILED( pxQueue );
95 return errQUEUE_FULL;
96 }
97 }
98 }
99 /*-----------------------------------------------------------*/
```
如果阻塞时间不为 0,任务会因为等待入队而进入阻塞, 在将任务设置为阻塞的过程中, 系统不希望有其它任务和中断操作这个队列的 xTasksWaitingToReceive 列表和 xTasksWaitingToSend 列表,因为可能引起其它任务解除阻塞,这可能会发生优先级翻转。比如任务 A 的优先级低于当前任务,但是在当前任务进入阻塞的过程中,任务 A 却因为其它原因解除阻塞了,这显然是要绝对禁止的。因此FreeRTOS 使用挂起调度器禁止其它任务操作队列,因为挂起调度器意味着任务不能切换并且不准调用可能引起任务切换的 API 函数。但挂起调度器并不会禁止中断,中断服务函数仍然可以操作队列阻塞列表,可能会解除任务阻塞、可能会进行上下文切换,这也是不允许的。于是,**FreeRTOS解决办法是不但挂起调度器,还要给队列上锁,禁止任何中断来操作队列。**
下面来看看流程图:
![消息队列发送流程](https://img2018.cnblogs.com/blog/1834930/201910/1834930-20191015204302894-1512501738.png)
相比在任务中调用的发送函数,在中断中调用的函数会更加简单一些, 没有任务阻塞操作。
函数 xQueueGenericSend中插入数据后, 会检查等待接收链表是否有任务等待,如果有会恢复就绪。如果恢复的任务优先级比当前任务高, 则会触发任务切换;但是在中断中调用的这个函数的做法是返回一个参数标志是否需要触发任务切换,并不在中断中切换任务。
在任务中调用的函数中有锁定和解锁队列的操作, 锁定队列的时候, 队列的事件链表不能被修改。 而在被中断中发送消息的处理是: 当遇到队列被锁定的时候, 将新数据插入到队列后, 并不会直接恢复因为等待接收的任务, 而是累加了计数, 当队列解锁的时候, 会根据这个计数, 对应恢复几个任务。
遇到队列满的情况, 函数会直接返回, 而不是阻塞等待, 因为在中断中阻塞是不允许的!!!
```
1 BaseType_t xQueueGenericSendFromISR(
2 QueueHandle_t xQueue,
3 const void * const pvItemToQueue,
4 /* 不在中断函数中触发任务切换, 而是返回一个标记 */
5 BaseType_t * const pxHigherPriorityTaskWoken,
6 const BaseType_t xCopyPosition )
7{
8 BaseType_t xReturn;
9 UBaseType_t uxSavedInterruptStatus;
10 Queue_t * const pxQueue = ( Queue_t * ) xQueue;
11
12 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
13 {
14 // 判断队列是否有空间插入新内容
15 if( ( pxQueue->uxMessagesWaiting uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
16 {
17 const int8_t cTxLock = pxQueue->cTxLock;
18
19 // 中断中不能使用互斥锁, 所以拷贝函数只是拷贝数据,
20 // 没有任务优先级继承需要考虑
21 ( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
22
23 // 判断队列是否被锁定
24 if( cTxLock == queueUNLOCKED )
25 {
26 #if ( configUSE_QUEUE_SETS == 1 )
27 // 集合相关代码
28 #else /* configUSE_QUEUE_SETS */
29 {
30 // 将最高优先级的等待任务恢复到就绪链表
31 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
32 {
33 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE)
34 {
35 // 如果有高优先级的任务被恢复
36 // 此处不直接触发任务切换, 而是返回一个标记
37 if( pxHigherPriorityTaskWoken != NULL )
38 {
39 *pxHigherPriorityTaskWoken = pdTRUE;
40 }
41 }
42 }
43 }
44 #endif /* configUSE_QUEUE_SETS */
45 }
46 else
47 {
48 // 队列被锁定, 不能修改事件链表
49 // 增加计数, 记录需要接触几个任务到就绪
50 // 在解锁队列的时候会根据这个计数恢复任务
51 pxQueue->cTxLock = ( int8_t ) ( cTxLock + 1 );
52 }
53 xReturn = pdPASS;
54 }
55 else
56 {
57 // 队列满 直接返回 不阻塞
58 xReturn = errQUEUE_FULL;
59 }
60 }
61
62 // 恢复中断的优先级
63 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
64
65 return xReturn;
66}
```
#### 消息队列读取
![消息读取](https://img2018.cnblogs.com/blog/1834930/201910/1834930-20191015204303126-254963658.png)
任务调用接收函数收取队列消息, 函数首先判断当前队列是否有未读消息, 如果没有, 则会判断参数 xTicksToWait, 决定直接返回函数还是阻塞等待。
如果队列中有消息未读, 首先会把待读的消息复制到传进来的指针所指内, 然后判断函数参数 xJustPeeking == pdFALSE的时候, 符合的话, 说明这个函数读取了数据, 需要把被读取的数据做出队处理, 如果不是, 则只是查看一下(peek),只是返回数据,但是不会把数据清除。
对于正常读取数据的操作, 清除数据后队列会空出空位, 所以查看队列中的等待列表中是否有任务等发送数据而被挂起, 有的话恢复一个任务就绪, 并根据优先级判断是否需要出进行任务切换。
对于只是查看数据的, 由于没有清除数据, 所以没有空间新空出,不需要检查发送等待链表, 但是会检查接收等待链表, 如果有任务挂起会切换其到就绪并判断是否需要切换。
消息队列出队过程分析,其实跟入队差不多,请看注释:
```
1 /*-----------------------------------------------------------*/
2 BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, (1)
3 void * const pvBuffer, (2)
4 TickType_t xTicksToWait, (3)
5 const BaseType_t xJustPeeking ) (4)
6 {
7 BaseType_t xEntryTimeSet = pdFALSE;
8 TimeOut_t xTimeOut;
9 int8_t *pcOriginalReadPosition;
10 Queue_t * const pxQueue = ( Queue_t * ) xQueue;
11
12 /* 已删除一些断言 */
13 for ( ;; ) {
14 taskENTER_CRITICAL(); (5)
15 {
16 const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;
17
18 /* 看看队列中有没有消息 */
19 if ( uxMessagesWaiting > ( UBaseType_t ) 0 ) { (6)
20 /*防止仅仅是读取消息,而不进行消息出队操作*/
21 pcOriginalReadPosition = pxQueue->u.pcReadFrom; (7)
22 /* 拷贝消息到用户指定存放区域pvBuffer */
23 prvCopyDataFromQueue( pxQueue, pvBuffer ); (8)
24
25 if ( xJustPeeking == pdFALSE ) { (9)
26 /* 读取消息并且消息出队 */
27 traceQUEUE_RECEIVE( pxQueue );
28
29 /* 获取了消息,当前消息队列的消息个数需要减一 */
30 pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; (10)
31 /* 判断一下消息队列中是否有等待发送消息的任务 */
32 if ( listLIST_IS_EMPTY( (11)
33 &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) {
34 /* 将任务从阻塞中恢复 */
35 if ( xTaskRemoveFromEventList( (12)
36 &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) {
37 /* 如果被恢复的任务优先级比当前任务高,会进行一次任务切换 */
38 queueYIELD_IF_USING_PREEMPTION(); (13)
39 } else {
40 mtCOVERAGE_TEST_MARKER();
41 }
42 } else {
43 mtCOVERAGE_TEST_MARKER();
44 }
45 } else { (14)
46 /* 任务只是看一下消息(peek),并不出队 */
47 traceQUEUE_PEEK( pxQueue );
48
49 /* 因为是只读消息 所以还要还原读消息位置指针 */
50 pxQueue->u.pcReadFrom = pcOriginalReadPosition; (15)
51
52 /* 判断一下消息队列中是否还有等待获取消息的任务 */
53 if ( listLIST_IS_EMPTY( (16)
54 &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) {
55 /* 将任务从阻塞中恢复 */
56 if ( xTaskRemoveFromEventList(
57 &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) {
58 /* 如果被恢复的任务优先级比当前任务高,会进行一次任务切换 */
59 queueYIELD_IF_USING_PREEMPTION();
60 } else {
61 mtCOVERAGE_TEST_MARKER();
62 }
63 } else {
64 mtCOVERAGE_TEST_MARKER();
65 }
66 }
67
68 taskEXIT_CRITICAL(); (17)
69 return pdPASS;
70 } else { (18)
71 /* 消息队列中没有消息可读 */
72 if ( xTicksToWait == ( TickType_t ) 0 ) { (19)
73 /* 不等待,直接返回 */
74 taskEXIT_CRITICAL();
75 traceQUEUE_RECEIVE_FAILED( pxQueue );
76 return errQUEUE_EMPTY;
77 } else if ( xEntryTimeSet == pdFALSE ) {
78 /* 初始化阻塞超时结构体变量,初始化进入
79 阻塞的时间xTickCount和溢出次数xNumOfOverflows */
80 vTaskSetTimeOutState( &xTimeOut ); (20)
81 xEntryTimeSet = pdTRUE;
82 } else {
83 mtCOVERAGE_TEST_MARKER();
84 }
85 }
86 }
87 taskEXIT_CRITICAL();
88
89 vTaskSuspendAll();
90 prvLockQueue( pxQueue ); (21)
91
92 /* 检查超时时间是否已经过去了*/
93 if ( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) {(22)
94 /* 如果队列还是空的 */
95 if ( prvIsQueueEmpty( pxQueue ) != pdFALSE ) {
96 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); (23)
97 /* 将当前任务添加到队列的等待接收列表中
98 以及阻塞延时列表,阻塞时间为用户指定的超时时间xTicksToWait */
99 vTaskPlaceOnEventList(
100 &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
101 prvUnlockQueue( pxQueue );
102 if ( xTaskResumeAll() == pdFALSE ) {
103 /* 如果有任务优先级比当前任务高,会进行一次任务切换 */
104 portYIELD_WITHIN_API();
105 } else {
106 mtCOVERAGE_TEST_MARKER();
107 }
108 } else {
109 /* 如果队列有消息了,就再试一次获取消息 */
110 prvUnlockQueue( pxQueue ); (24)
111 ( void ) xTaskResumeAll();
112 }
113 } else {
114 /* 超时时间已过,退出 */
115 prvUnlockQueue( pxQueue ); (25)
116 ( void ) xTaskResumeAll();
117
118 if ( prvIsQueueEmpty( pxQueue ) != pdFALSE ) {
119 /* 如果队列还是空的,返回错误代码errQUEUE_EMPTY */
120 traceQUEUE_RECEIVE_FAILED( pxQueue );
121 return errQUEUE_EMPTY; (26)
122 } else {
123 mtCOVERAGE_TEST_MARKER();
124 }
125 }
126 }
127 }
128 /*-----------------------------------------------------------*/
```
### 提示
如果队列存储的数据较大时,那最好是利用队列来传递数据的指针而不是数据本身,因为传递数据的时候是需要CPU一字节一字节地将数据拷贝进队列或从队列拷贝出来。而传递指针无论是在处理速度上还是内存空间利用上都更有效。但是,当利用队列传递指针时,一定要十分小心地做到以下两点:
#### 1.指针指向的内存空间的所有权必须明确
当任务间通过指针共享内存时,应该从根本上保证所不会有任意两个任务同时修改共享内存中的数据,或是以其它行为方式使得共享内存数据无效或产生一致性问题。原则上,共享内存在其指针发送到队列之前,其内容只允许被发送任务访问;共享内存指针从队列中被读出之后,其内容亦只允许被接收任务访问。
#### 2.指针指向的内存空间必须有效
如果指针指向的内存空间是动态分配的,只应该有一个任务负责对其进行内存释放。当这段内存空间被释放之后,就不应该有任何一个任务再访问这段空间。
并且最最最重要的是禁止使用指针访问**任务栈上**的空间,也就是局部变量。因为当栈发生改变后,栈上的数据将不再有效。
# 关注我
![欢迎关注我公众号](https://img2018.cnblogs.com/blog/1834930/201910/1834930-20191015204303727-1157345454.jpg)
更多资料欢迎关注“物联网IoT开发”公众号!
从0开始学FreeRTOS-(消息队列)-5的更多相关文章
- FreeRTOS 消息队列
以下基础内容转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 的一个重要的通信机制----消息队列,初学者要熟练掌握,因为消息 ...
- FreeRTOS消息队列
FreeRTOS 的一个重要的通信机制----消息队列,消息队列在实际项目中应用较多. 一.消息队列的作用及概念: 消息队列就是通过 RTOS 内核提供的服务,任务或中断服务子程序可以将一个消息(注意 ...
- 继续学习freertos消息队列
写在前面:杰杰这个月很忙~所以并没有时间更新,现在健身房闭馆装修,晚上有空就更新一下!其实在公众号没更新的这段日子,每天都有兄弟在来关注我的公众号,这让我受宠若惊,在这里谢谢大家的支持啦!!谢谢^ 在 ...
- PetShop 4.0学习笔记:消息队列MSMQ
直到今天才知道,在我们每天都在用的Window系统里还有这么好用的一个编程组件:消息队列.它能够解决在大数据量交换的情况下的性能问题,特别是BS系统的数据库性能.而且它的异步处理方式能给程序员最大的便 ...
- CentOS 7.0 安装配置 kafka 消息队列
查询下载最新版本 kafka http://kafka.apache.org/downloads.html wget http://mirror.bit.edu.cn/apache/kafka/0.8 ...
- 【FreeRTOS学习04】小白都能懂的 Queue Management 消息队列使用详解
消息队列作为任务间同步扮演着必不可少的角色: 相关文章 [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 相关文章 1 前言 2 xQUEUE 3 相关概念 3 ...
- Python并发编程之消息队列补充及如何创建线程池(六)
大家好,并发编程 进入第六篇. 在第四章,讲消息通信时,我们学到了Queue消息队列的一些基本使用.昨天我在准备如何创建线程池这一章节的时候,发现对Queue消息队列的讲解有一些遗漏的知识点,而这些知 ...
- Linux进程间通信(七):消息队列 msgget()、msgsend()、msgrcv()、msgctl()
下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信 -- 使用命名管道 一.什么是消息队列 消息队列提 ...
- [转]Linux进程间通信——使用消息队列
点击此处阅读原文 另收藏作者ljianhui的专栏初学Linux 下面来说说如何使用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linu ...
随机推荐
- 爬虫基本知识之C/S交互
概念 爬虫就是对网页的获取. 一般获取的网页中又有通向其他网页的通路,我们叫做超链接,那么就可以通过这样的通路获取更多其他的网页,就像一只在网路上爬行的蜘蛛,所以俗称爬虫. 爬虫的工作原理和浏览器浏览 ...
- 【Offer】[25] 【合并两个排序的链表】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的.例如,输入图中的链表1和链表2,则合并之后的升序链表如链表3所 ...
- 【Offer】[4] 【二维数组中的查找】
题目描述 思路分析 Java代码 代码链接 题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数 ...
- git 中文乱码-一次被坑经历
git log和gitcommit中文出现乱码,花了大半天的时间试了网上的各种方法,还是搞不定. 只好放大招. 卸载软件后重装,还是不行.然后git config --list 发现一些奇怪的配置信息 ...
- 并发之初章Java内存模型
>>>>>>博客地址<<<<<< >>>>>>首发博客<<<<< ...
- Redis删除集群以及重新启动集群
有时候我们搭建完集群以后,对集群进行了一些错误的操作,导致集群出现了不可预料的问题,这时候想要删除集群重新启动一个原始的集群,那么如何删除原来旧的集群呢? 1.关闭所有开启的Redis节点 kill ...
- centos 7 ifconfig无法找到命令的方法
场景:新安装centos 没有安装. centos7.2的mini版没有安装这个东东,所以我们就直接安装就好了,在终端里面输入: yum -y install net-tools
- HDFS之Qurom Journal Manager(QJM)实现机制分析
前言 1.1背景 自从hadoop2版本开始,社区引入了NameNode高可用方案.NameNode主从节点间需要同步操作日志来达到主从节点元数据一致.最初业界均通过NFS来实现日志同步,大家之所以选 ...
- xml文档的解析并通过工具类实现java实体类的映射:XML工具-XmlUtil
若有疑问,可以联系我本人微信:Y1141100952 声明:本文章为原稿,转载必须说明 本文章地址,否则一旦发现,必追究法律责任 1:本文章显示通过 XML工具-XmlUtil工具实现解析soap报文 ...
- The 10 Most Important Linux Commands/10个最经常使用的命令行
1. ls 命令:to show all of the major directiories filed under a given file system. for example: ls /app ...