- 减少pthread_cond_signal和sem_post的调用,只在有必要的时候调用;
- 尽量避免pthread_mutex进入竞争态。增大消息队列的大小,可以有效减少竞态条件的出现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | #include <iostream> #include <pthread.h> class CThreadQueue { public: CThreadQueue (int queueSize = 1024): sizeQueue (queueSize), lput (0), lget (0), nFullThread (0), nEmptyThread (0), nData (0) { pthread_mutex_init (&mux, 0); pthread_cond_init (&condGet, 0); pthread_cond_init (&condPut, 0); buffer = new void *[sizeQueue]; } virtual ~ CThreadQueue () { pthread_mutex_destroy (&mux); pthread_cond_destroy (&condGet); pthread_cond_destroy (&condPut); delete[]buffer; } void *getq () { void *data; pthread_mutex_lock (&mux); /* * 此处循环判断的原因如下:假设2个线程在getq阻塞,然后两者都被激活, * 而其中一个线程运行比较块,快速消耗了2个数据, * 另一个线程醒来的时候已经没有新数据可以消耗了。 * 另一点,man pthread_cond_wait可以看到, * 该函数可以被信号中断返回,此时返回EINTR。 * 为避免以上任何一点,都必须醒来后再次判断睡眠条件。 * 更正:pthread_cond_wait是信号安全的系统调用,不会被信号中断。 */ while (lget == lput && nData == 0) { nEmptyThread++; pthread_cond_wait (&condGet, &mux); nEmptyThread--; } data = buffer[lget++]; nData--; if (lget == sizeQueue) { lget = 0; } if (nFullThread) //必要时才进行signal操作,勿总是signal { pthread_cond_signal (&condPut); } pthread_mutex_unlock (&mux); return data; } void putq (void *data) { pthread_mutex_lock (&mux); while (lput == lget && nData) { nFullThread++; pthread_cond_wait (&condPut, &mux); nFullThread--; } buffer[lput++] = data; nData++; if (lput == sizeQueue) { lput = 0; } if (nEmptyThread) { pthread_cond_signal (&condGet); } pthread_mutex_unlock (&mux); } private: pthread_mutex_t mux; pthread_cond_t condGet; pthread_cond_t condPut; void **buffer; //循环消息队列 int sizeQueue; //队列大小 int lput; //location put 放数据的指针偏移 int lget; //location get 取数据的指针偏移 int nFullThread; //队列满,阻塞在putq处的线程数 int nEmptyThread; //队列空,阻塞在getq处的线程数 int nData; //队列中的消息个数,主要用来判断队列空还是满 }; //使用的时候给出稍大的CThreadQueue初始化参数,可以减少进入内核态的操作。 CThreadQueue queue; void * produce (void *arg) { int i = 0; pthread_detach (pthread_self ()); while (i++ < 100) { queue.putq ((void *) i); } } void * consume (void *arg) { int data; while (1) { data = (int) (queue.getq ()); printf ("data=%d\n", data); } } int main () { pthread_t pid; int i = 0; while (i++ < 3) pthread_create (&pid, 0, produce, 0); i = 0; while (i++ < 3) pthread_create (&pid, 0, consume, 0); sleep (30); return 0; } |
你好!除了代码,此处没有多少原创之物,皆为本人搜集、整理、总结之记录与心得,欢迎转载分享!转载时请尽量注明出处,将不胜感激。祝你健康、快乐!
RFC: Request For Comments. Orz..
Be the first to comment on this entry.