1. #include <stdio.h>
2. #include <pthread.h>
3. #define BUFFER_SIZE 16 // 缓冲区数量
4. struct prodcons
5. {
6. // 缓冲区相关数据结构
7. int buffer[BUFFER_SIZE]; /* 实际数据存放的数组*/
8. pthread_mutex_t lock; /* 互斥体lock 用于对缓冲区的互斥操作 */
9. int readpos, writepos; /* 读写指针*/
10. pthread_cond_t notempty; /* 缓冲区非空的条件变量 */
11. pthread_cond_t notfull; /* 缓冲区未满的条件变量 */
12. };
13. /* 初始化缓冲区结构 */
14. void init(struct prodcons *b)
15. {
16. pthread_mutex_init(&b->lock, NULL);
17. pthread_cond_init(&b->notempty, NULL);
18. pthread_cond_init(&b->notfull, NULL);
19. b->readpos = 0;
20. b->writepos = 0;
21. }
22. /* 将产品放入缓冲区,这里是存入一个整数*/
23. void put(struct prodcons *b, int data)
24. {
25. pthread_mutex_lock(&b->lock);
26. /* 等待缓冲区未满*/
27. if ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
28. {
29. pthread_cond_wait(&b->notfull, &b->lock);
30. }
31. /* 写数据,并移动指针 */
32. b->buffer[b->writepos] = data;
33. b->writepos++;
34. if (b->writepos > = BUFFER_SIZE)
35. b->writepos = 0;
36. /* 设置缓冲区非空的条件变量*/
37. pthread_cond_signal(&b->notempty);
38. pthread_mutex_unlock(&b->lock);
39. }
40.
41. /* 从缓冲区中取出整数*/
42. int get(struct prodcons *b)
43. {
44. int data;
45. pthread_mutex_lock(&b->lock);
46. /* 等待缓冲区非空*/
47. if (b->writepos == b->readpos)
48. {
49. pthread_cond_wait(&b->notempty, &b->lock);
50. }
51. /* 读数据,移动读指针*/
52. data = b->buffer[b->readpos];
53. b->readpos++;
54. if (b->readpos > = BUFFER_SIZE)
55. b->readpos = 0;
56. /* 设置缓冲区未满的条件变量*/
57. pthread_cond_signal(&b->notfull);
58. pthread_mutex_unlock(&b->lock);
59. return data;
60. }
61.
62. /* 测试:生产者线程将1 到10000 的整数送入缓冲区,消费者线
63. 程从缓冲区中获取整数,两者都打印信息*/
64. #define OVER ( - 1)
65. struct prodcons buffer;
66. void *producer(void *data)
67. {
68. int n;
69. for (n = 0; n < 10000; n++)
70. {
71. printf("%d --->\n", n);
72. put(&buffer, n);
73. } put(&buffer, OVER);
74. return NULL;
75. }
76.
77. void *consumer(void *data)
78. {
79. int d;
80. while (1)
81. {
82. d = get(&buffer);
83. if (d == OVER)
84. break;
85. printf("--->%d \n", d);
86. }
87. return NULL;
88. }
89.
90. int main(void)
91. {
92. pthread_t th_a, th_b;
93. void *retval;
94. init(&buffer);
95. /* 创建生产者和消费者线程*/
96. pthread_create(&th_a, NULL, producer, 0);
97. pthread_create(&th_b, NULL, consumer, 0);
98. /* 等待两个线程结束*/
99. pthread_join(th_a, &retval);
100. pthread_join(th_b, &retval);
101. return 0;
102. }
现在我想实现类似这样的:生产者每生产一个data,供两个消费者消费,
等这两个消费者都消费完同一个data,才能写入新的data。
另外这两个消费者同时消费,互不干扰,尽可能并发,代码应该如何写呢?
8 个解决方案
#1
帮顶
#2
定义一对标志位,如
bool resumed[2]; // 0表示消费者A,1表示消费者B
消费者消费后置位各自的标志位
生产者根据标志位决定生产并重置标志位
或者定义一个计数器,如
int counter;
也是类似上述的想法,不过就是要多一个AB之间更新此counter的同步
bool resumed[2]; // 0表示消费者A,1表示消费者B
消费者消费后置位各自的标志位
生产者根据标志位决定生产并重置标志位
或者定义一个计数器,如
int counter;
也是类似上述的想法,不过就是要多一个AB之间更新此counter的同步
#3
用标志位的话是不是要频繁的查询这个标志位?
#4
仅供参考
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#include <io.h>
#else
#include <unistd.h>
#include <sys/time.h>
#include <pthread.h>
#define CRITICAL_SECTION pthread_mutex_t
#define _vsnprintf vsnprintf
#endif
//Log{
#define MAXLOGSIZE 20000000
#define ARRSIZE(x) (sizeof(x)/sizeof(x[0]))
#include <time.h>
#include <sys/timeb.h>
#include <stdarg.h>
char logfilename1[]="MyLog1.log";
char logfilename2[]="MyLog2.log";
char logstr[16000];
char datestr[16];
char timestr[16];
char mss[4];
CRITICAL_SECTION cs_log;
FILE *flog;
#ifdef WIN32
void Lock(CRITICAL_SECTION *l) {
EnterCriticalSection(l);
}
void Unlock(CRITICAL_SECTION *l) {
LeaveCriticalSection(l);
}
#else
void Lock(CRITICAL_SECTION *l) {
pthread_mutex_lock(l);
}
void Unlock(CRITICAL_SECTION *l) {
pthread_mutex_unlock(l);
}
#endif
void LogV(const char *pszFmt,va_list argp) {
struct tm *now;
struct timeb tb;
if (NULL==pszFmt||0==pszFmt[0]) return;
if (-1==_vsnprintf(logstr,ARRSIZE(logstr),pszFmt,argp)) logstr[ARRSIZE(logstr)-1]=0;
ftime(&tb);
now=localtime(&tb.time);
sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);
sprintf(timestr,"%02d:%02d:%02d",now->tm_hour ,now->tm_min ,now->tm_sec );
sprintf(mss,"%03d",tb.millitm);
printf("%s %s.%s %s",datestr,timestr,mss,logstr);
flog=fopen(logfilename1,"a");
if (NULL!=flog) {
fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);
if (ftell(flog)>MAXLOGSIZE) {
fclose(flog);
if (rename(logfilename1,logfilename2)) {
remove(logfilename2);
rename(logfilename1,logfilename2);
}
flog=fopen(logfilename1,"a");
if (NULL==flog) return;
}
fclose(flog);
}
}
void Log(const char *pszFmt,...) {
va_list argp;
Lock(&cs_log);
va_start(argp,pszFmt);
LogV(pszFmt,argp);
va_end(argp);
Unlock(&cs_log);
}
//Log}
int main(int argc,char * argv[]) {
int i;
#ifdef WIN32
InitializeCriticalSection(&cs_log);
#else
pthread_mutex_init(&cs_log,NULL);
#endif
for (i=0;i<10000;i++) {
Log("This is a Log %04d from FILE:%s LINE:%d\n",i, __FILE__, __LINE__);
}
#ifdef WIN32
DeleteCriticalSection(&cs_log);
#else
pthread_mutex_destroy(&cs_log);
#endif
return 0;
}
//循环向a函数每次发送200个字节长度(这个是固定的)的buffer,
//a函数中需要将循环传进来的buffer,组成240字节(也是固定的)的新buffer进行处理,
//在处理的时候每次从新buffer中取两个字节打印
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <process.h>
#include <io.h>
//Log{
#define MAXLOGSIZE 10000000
#define ARRSIZE(x) (sizeof(x)/sizeof(x[0]))
#include <time.h>
#include <sys/timeb.h>
#include <stdarg.h>
char logfilename1[]="MyLog1.log";
char logfilename2[]="MyLog2.log";
char logstr[16000];
char datestr[16];
char timestr[16];
char mss[4];
CRITICAL_SECTION cs_log;
FILE *flog;
void Lock(CRITICAL_SECTION *l) {
EnterCriticalSection(l);
}
void Unlock(CRITICAL_SECTION *l) {
LeaveCriticalSection(l);
}
void LogV(const char *pszFmt,va_list argp) {
struct tm *now;
struct timeb tb;
if (NULL==pszFmt||0==pszFmt[0]) return;
if (-1==_vsnprintf(logstr,ARRSIZE(logstr),pszFmt,argp)) logstr[ARRSIZE(logstr)-1]=0;
ftime(&tb);
now=localtime(&tb.time);
sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);
sprintf(timestr,"%02d:%02d:%02d",now->tm_hour ,now->tm_min ,now->tm_sec );
sprintf(mss,"%03d",tb.millitm);
printf("%s %s.%s %s",datestr,timestr,mss,logstr);
flog=fopen(logfilename1,"a");
if (NULL!=flog) {
fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);
if (ftell(flog)>MAXLOGSIZE) {
fclose(flog);
if (rename(logfilename1,logfilename2)) {
remove(logfilename2);
rename(logfilename1,logfilename2);
}
flog=fopen(logfilename1,"a");
if (NULL==flog) return;
}
fclose(flog);
}
}
void Log(const char *pszFmt,...) {
va_list argp;
Lock(&cs_log);
va_start(argp,pszFmt);
LogV(pszFmt,argp);
va_end(argp);
Unlock(&cs_log);
}
//Log}
#define ASIZE 200
#define BSIZE 240
#define CSIZE 2
char Abuf[ASIZE];
char Cbuf[CSIZE];
CRITICAL_SECTION cs_HEX ;
CRITICAL_SECTION cs_BBB ;
struct FIFO_BUFFER {
int head;
int tail;
int size;
char data[BSIZE];
} BBB;
int No_Loop=0;
void HexDump(int cn,char *buf,int len) {
int i,j,k;
char binstr[80];
Lock(&cs_HEX);
for (i=0;i<len;i++) {
if (0==(i%16)) {
sprintf(binstr,"%03d %04x -",cn,i);
sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
} else if (15==(i%16)) {
sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
sprintf(binstr,"%s ",binstr);
for (j=i-15;j<=i;j++) {
sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');
}
Log("%s\n",binstr);
} else {
sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
}
}
if (0!=(i%16)) {
k=16-(i%16);
for (j=0;j<k;j++) {
sprintf(binstr,"%s ",binstr);
}
sprintf(binstr,"%s ",binstr);
k=16-k;
for (j=i-k;j<i;j++) {
sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');
}
Log("%s\n",binstr);
}
Unlock(&cs_HEX);
}
int GetFromRBuf(int cn,CRITICAL_SECTION *cs,FIFO_BUFFER *fbuf,char *buf,int len) {
int lent,len1,len2;
lent=0;
Lock(cs);
if (fbuf->size>=len) {
lent=len;
if (fbuf->head+lent>BSIZE) {
len1=BSIZE-fbuf->head;
memcpy(buf ,fbuf->data+fbuf->head,len1);
len2=lent-len1;
memcpy(buf+len1,fbuf->data ,len2);
fbuf->head=len2;
} else {
memcpy(buf ,fbuf->data+fbuf->head,lent);
fbuf->head+=lent;
}
fbuf->size-=lent;
}
Unlock(cs);
return lent;
}
void thdB(void *pcn) {
char *recv_buf;
int recv_nbytes;
int cn;
int wc;
int pb;
cn=(int)pcn;
Log("%03d thdB thread begin...\n",cn);
while (1) {
Sleep(10);
recv_buf=(char *)Cbuf;
recv_nbytes=CSIZE;
wc=0;
while (1) {
pb=GetFromRBuf(cn,&cs_BBB,&BBB,recv_buf,recv_nbytes);
if (pb) {
Log("%03d recv %d bytes\n",cn,pb);
HexDump(cn,recv_buf,pb);
Sleep(1);
} else {
Sleep(1000);
}
if (No_Loop) break;//
wc++;
if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);
}
if (No_Loop) break;//
}
}
int PutToRBuf(int cn,CRITICAL_SECTION *cs,FIFO_BUFFER *fbuf,char *buf,int len) {
int lent,len1,len2;
Lock(cs);
lent=len;
if (fbuf->size+lent>BSIZE) {
lent=BSIZE-fbuf->size;
}
if (fbuf->tail+lent>BSIZE) {
len1=BSIZE-fbuf->tail;
memcpy(fbuf->data+fbuf->tail,buf ,len1);
len2=lent-len1;
memcpy(fbuf->data ,buf+len1,len2);
fbuf->tail=len2;
} else {
memcpy(fbuf->data+fbuf->tail,buf ,lent);
fbuf->tail+=lent;
}
fbuf->size+=lent;
Unlock(cs);
return lent;
}
void thdA(void *pcn) {
char *send_buf;
int send_nbytes;
int cn;
int wc;
int a;
int pa;
cn=(int)pcn;
Log("%03d thdA thread begin...\n",cn);
a=0;
while (1) {
Sleep(100);
memset(Abuf,a,ASIZE);
a=(a+1)%256;
if (16==a) {No_Loop=1;break;}//去掉这句可以让程序一直循环直到按Ctrl+C或Ctrl+Break或当前目录下存在文件No_Loop
send_buf=(char *)Abuf;
send_nbytes=ASIZE;
Log("%03d sending %d bytes\n",cn,send_nbytes);
HexDump(cn,send_buf,send_nbytes);
wc=0;
while (1) {
pa=PutToRBuf(cn,&cs_BBB,&BBB,send_buf,send_nbytes);
Log("%03d sent %d bytes\n",cn,pa);
HexDump(cn,send_buf,pa);
send_buf+=pa;
send_nbytes-=pa;
if (send_nbytes<=0) break;//
Sleep(1000);
if (No_Loop) break;//
wc++;
if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);
}
if (No_Loop) break;//
}
}
int main() {
InitializeCriticalSection(&cs_log );
Log("Start===========================================================\n");
InitializeCriticalSection(&cs_HEX );
InitializeCriticalSection(&cs_BBB );
BBB.head=0;
BBB.tail=0;
BBB.size=0;
_beginthread((void(__cdecl *)(void *))thdA,0,(void *)1);
_beginthread((void(__cdecl *)(void *))thdB,0,(void *)2);
if (!access("No_Loop",0)) {
remove("No_Loop");
if (!access("No_Loop",0)) {
No_Loop=1;
}
}
while (1) {
Sleep(1000);
if (No_Loop) break;//
if (!access("No_Loop",0)) {
No_Loop=1;
}
}
Sleep(3000);
DeleteCriticalSection(&cs_BBB );
DeleteCriticalSection(&cs_HEX );
Log("End=============================================================\n");
DeleteCriticalSection(&cs_log );
return 0;
}
#5
本人新手,试了一下,仅供参考。
编译命令: gcc producer_customer.c -pthread -Wall -std=c99
编译命令: gcc producer_customer.c -pthread -Wall -std=c99
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h>
struct {
char buf[2];
bool cc1, cc2;
} *production = NULL;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_producter = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_customer = PTHREAD_COND_INITIALIZER;
void *producter(void *argv)
{
while(1) {
pthread_mutex_lock(&mutex);
if(!production) {
production = malloc(sizeof(*production));
strcpy(production->buf, "a");
} else {
while(production->cc1 || production->cc2)
pthread_cond_wait(&cond_customer, &mutex);
char c = production->buf[0] + 1;
production->buf[0] = c > 'z' ? 'a' : c;
}
production->cc1 = production->cc2 = true;
pthread_cond_signal(&cond_producter);
pthread_mutex_unlock(&mutex);
}
}
void *customer1(void *argv)
{
while(1) {
pthread_mutex_lock(&mutex);
while(!production || !production->cc1)
pthread_cond_wait(&cond_producter, &mutex);
printf("custom 1: %s\n", production->buf);
production->cc1 = false;
if(!production->cc2)
pthread_cond_signal(&cond_customer);
else
pthread_cond_signal(&cond_producter);
pthread_mutex_unlock(&mutex);
}
}
void *customer2(void *argv)
{
while(1) {
pthread_mutex_lock(&mutex);
while(!production || !production->cc2)
pthread_cond_wait(&cond_producter, &mutex);
printf("custom 2: %s\n", production->buf);
production->cc2 = false;
if(!production->cc1)
pthread_cond_signal(&cond_customer);
else
pthread_cond_signal(&cond_producter);
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, NULL, customer1, NULL);
pthread_create(&tid, NULL, customer2, NULL);
pthread_create(&tid, NULL, producter, NULL);
pthread_join(tid, NULL);
free(production);
return 0;
}
#6
程序中的三处等待条件变量的地方可以不用while循环的,只用if判断就行了。
#7
是应该用while判断,因为有可能发送虚假唤醒:期待的条件尚不成立的唤醒。
详见 UNIX网络编程 卷2:进程间通信。135页(中文翻译版)。
#8
以前还真没注意,受教了啊
#1
帮顶
#2
定义一对标志位,如
bool resumed[2]; // 0表示消费者A,1表示消费者B
消费者消费后置位各自的标志位
生产者根据标志位决定生产并重置标志位
或者定义一个计数器,如
int counter;
也是类似上述的想法,不过就是要多一个AB之间更新此counter的同步
bool resumed[2]; // 0表示消费者A,1表示消费者B
消费者消费后置位各自的标志位
生产者根据标志位决定生产并重置标志位
或者定义一个计数器,如
int counter;
也是类似上述的想法,不过就是要多一个AB之间更新此counter的同步
#3
用标志位的话是不是要频繁的查询这个标志位?
#4
仅供参考
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#include <io.h>
#else
#include <unistd.h>
#include <sys/time.h>
#include <pthread.h>
#define CRITICAL_SECTION pthread_mutex_t
#define _vsnprintf vsnprintf
#endif
//Log{
#define MAXLOGSIZE 20000000
#define ARRSIZE(x) (sizeof(x)/sizeof(x[0]))
#include <time.h>
#include <sys/timeb.h>
#include <stdarg.h>
char logfilename1[]="MyLog1.log";
char logfilename2[]="MyLog2.log";
char logstr[16000];
char datestr[16];
char timestr[16];
char mss[4];
CRITICAL_SECTION cs_log;
FILE *flog;
#ifdef WIN32
void Lock(CRITICAL_SECTION *l) {
EnterCriticalSection(l);
}
void Unlock(CRITICAL_SECTION *l) {
LeaveCriticalSection(l);
}
#else
void Lock(CRITICAL_SECTION *l) {
pthread_mutex_lock(l);
}
void Unlock(CRITICAL_SECTION *l) {
pthread_mutex_unlock(l);
}
#endif
void LogV(const char *pszFmt,va_list argp) {
struct tm *now;
struct timeb tb;
if (NULL==pszFmt||0==pszFmt[0]) return;
if (-1==_vsnprintf(logstr,ARRSIZE(logstr),pszFmt,argp)) logstr[ARRSIZE(logstr)-1]=0;
ftime(&tb);
now=localtime(&tb.time);
sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);
sprintf(timestr,"%02d:%02d:%02d",now->tm_hour ,now->tm_min ,now->tm_sec );
sprintf(mss,"%03d",tb.millitm);
printf("%s %s.%s %s",datestr,timestr,mss,logstr);
flog=fopen(logfilename1,"a");
if (NULL!=flog) {
fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);
if (ftell(flog)>MAXLOGSIZE) {
fclose(flog);
if (rename(logfilename1,logfilename2)) {
remove(logfilename2);
rename(logfilename1,logfilename2);
}
flog=fopen(logfilename1,"a");
if (NULL==flog) return;
}
fclose(flog);
}
}
void Log(const char *pszFmt,...) {
va_list argp;
Lock(&cs_log);
va_start(argp,pszFmt);
LogV(pszFmt,argp);
va_end(argp);
Unlock(&cs_log);
}
//Log}
int main(int argc,char * argv[]) {
int i;
#ifdef WIN32
InitializeCriticalSection(&cs_log);
#else
pthread_mutex_init(&cs_log,NULL);
#endif
for (i=0;i<10000;i++) {
Log("This is a Log %04d from FILE:%s LINE:%d\n",i, __FILE__, __LINE__);
}
#ifdef WIN32
DeleteCriticalSection(&cs_log);
#else
pthread_mutex_destroy(&cs_log);
#endif
return 0;
}
//循环向a函数每次发送200个字节长度(这个是固定的)的buffer,
//a函数中需要将循环传进来的buffer,组成240字节(也是固定的)的新buffer进行处理,
//在处理的时候每次从新buffer中取两个字节打印
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <process.h>
#include <io.h>
//Log{
#define MAXLOGSIZE 10000000
#define ARRSIZE(x) (sizeof(x)/sizeof(x[0]))
#include <time.h>
#include <sys/timeb.h>
#include <stdarg.h>
char logfilename1[]="MyLog1.log";
char logfilename2[]="MyLog2.log";
char logstr[16000];
char datestr[16];
char timestr[16];
char mss[4];
CRITICAL_SECTION cs_log;
FILE *flog;
void Lock(CRITICAL_SECTION *l) {
EnterCriticalSection(l);
}
void Unlock(CRITICAL_SECTION *l) {
LeaveCriticalSection(l);
}
void LogV(const char *pszFmt,va_list argp) {
struct tm *now;
struct timeb tb;
if (NULL==pszFmt||0==pszFmt[0]) return;
if (-1==_vsnprintf(logstr,ARRSIZE(logstr),pszFmt,argp)) logstr[ARRSIZE(logstr)-1]=0;
ftime(&tb);
now=localtime(&tb.time);
sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);
sprintf(timestr,"%02d:%02d:%02d",now->tm_hour ,now->tm_min ,now->tm_sec );
sprintf(mss,"%03d",tb.millitm);
printf("%s %s.%s %s",datestr,timestr,mss,logstr);
flog=fopen(logfilename1,"a");
if (NULL!=flog) {
fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);
if (ftell(flog)>MAXLOGSIZE) {
fclose(flog);
if (rename(logfilename1,logfilename2)) {
remove(logfilename2);
rename(logfilename1,logfilename2);
}
flog=fopen(logfilename1,"a");
if (NULL==flog) return;
}
fclose(flog);
}
}
void Log(const char *pszFmt,...) {
va_list argp;
Lock(&cs_log);
va_start(argp,pszFmt);
LogV(pszFmt,argp);
va_end(argp);
Unlock(&cs_log);
}
//Log}
#define ASIZE 200
#define BSIZE 240
#define CSIZE 2
char Abuf[ASIZE];
char Cbuf[CSIZE];
CRITICAL_SECTION cs_HEX ;
CRITICAL_SECTION cs_BBB ;
struct FIFO_BUFFER {
int head;
int tail;
int size;
char data[BSIZE];
} BBB;
int No_Loop=0;
void HexDump(int cn,char *buf,int len) {
int i,j,k;
char binstr[80];
Lock(&cs_HEX);
for (i=0;i<len;i++) {
if (0==(i%16)) {
sprintf(binstr,"%03d %04x -",cn,i);
sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
} else if (15==(i%16)) {
sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
sprintf(binstr,"%s ",binstr);
for (j=i-15;j<=i;j++) {
sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');
}
Log("%s\n",binstr);
} else {
sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
}
}
if (0!=(i%16)) {
k=16-(i%16);
for (j=0;j<k;j++) {
sprintf(binstr,"%s ",binstr);
}
sprintf(binstr,"%s ",binstr);
k=16-k;
for (j=i-k;j<i;j++) {
sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');
}
Log("%s\n",binstr);
}
Unlock(&cs_HEX);
}
int GetFromRBuf(int cn,CRITICAL_SECTION *cs,FIFO_BUFFER *fbuf,char *buf,int len) {
int lent,len1,len2;
lent=0;
Lock(cs);
if (fbuf->size>=len) {
lent=len;
if (fbuf->head+lent>BSIZE) {
len1=BSIZE-fbuf->head;
memcpy(buf ,fbuf->data+fbuf->head,len1);
len2=lent-len1;
memcpy(buf+len1,fbuf->data ,len2);
fbuf->head=len2;
} else {
memcpy(buf ,fbuf->data+fbuf->head,lent);
fbuf->head+=lent;
}
fbuf->size-=lent;
}
Unlock(cs);
return lent;
}
void thdB(void *pcn) {
char *recv_buf;
int recv_nbytes;
int cn;
int wc;
int pb;
cn=(int)pcn;
Log("%03d thdB thread begin...\n",cn);
while (1) {
Sleep(10);
recv_buf=(char *)Cbuf;
recv_nbytes=CSIZE;
wc=0;
while (1) {
pb=GetFromRBuf(cn,&cs_BBB,&BBB,recv_buf,recv_nbytes);
if (pb) {
Log("%03d recv %d bytes\n",cn,pb);
HexDump(cn,recv_buf,pb);
Sleep(1);
} else {
Sleep(1000);
}
if (No_Loop) break;//
wc++;
if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);
}
if (No_Loop) break;//
}
}
int PutToRBuf(int cn,CRITICAL_SECTION *cs,FIFO_BUFFER *fbuf,char *buf,int len) {
int lent,len1,len2;
Lock(cs);
lent=len;
if (fbuf->size+lent>BSIZE) {
lent=BSIZE-fbuf->size;
}
if (fbuf->tail+lent>BSIZE) {
len1=BSIZE-fbuf->tail;
memcpy(fbuf->data+fbuf->tail,buf ,len1);
len2=lent-len1;
memcpy(fbuf->data ,buf+len1,len2);
fbuf->tail=len2;
} else {
memcpy(fbuf->data+fbuf->tail,buf ,lent);
fbuf->tail+=lent;
}
fbuf->size+=lent;
Unlock(cs);
return lent;
}
void thdA(void *pcn) {
char *send_buf;
int send_nbytes;
int cn;
int wc;
int a;
int pa;
cn=(int)pcn;
Log("%03d thdA thread begin...\n",cn);
a=0;
while (1) {
Sleep(100);
memset(Abuf,a,ASIZE);
a=(a+1)%256;
if (16==a) {No_Loop=1;break;}//去掉这句可以让程序一直循环直到按Ctrl+C或Ctrl+Break或当前目录下存在文件No_Loop
send_buf=(char *)Abuf;
send_nbytes=ASIZE;
Log("%03d sending %d bytes\n",cn,send_nbytes);
HexDump(cn,send_buf,send_nbytes);
wc=0;
while (1) {
pa=PutToRBuf(cn,&cs_BBB,&BBB,send_buf,send_nbytes);
Log("%03d sent %d bytes\n",cn,pa);
HexDump(cn,send_buf,pa);
send_buf+=pa;
send_nbytes-=pa;
if (send_nbytes<=0) break;//
Sleep(1000);
if (No_Loop) break;//
wc++;
if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);
}
if (No_Loop) break;//
}
}
int main() {
InitializeCriticalSection(&cs_log );
Log("Start===========================================================\n");
InitializeCriticalSection(&cs_HEX );
InitializeCriticalSection(&cs_BBB );
BBB.head=0;
BBB.tail=0;
BBB.size=0;
_beginthread((void(__cdecl *)(void *))thdA,0,(void *)1);
_beginthread((void(__cdecl *)(void *))thdB,0,(void *)2);
if (!access("No_Loop",0)) {
remove("No_Loop");
if (!access("No_Loop",0)) {
No_Loop=1;
}
}
while (1) {
Sleep(1000);
if (No_Loop) break;//
if (!access("No_Loop",0)) {
No_Loop=1;
}
}
Sleep(3000);
DeleteCriticalSection(&cs_BBB );
DeleteCriticalSection(&cs_HEX );
Log("End=============================================================\n");
DeleteCriticalSection(&cs_log );
return 0;
}
#5
本人新手,试了一下,仅供参考。
编译命令: gcc producer_customer.c -pthread -Wall -std=c99
编译命令: gcc producer_customer.c -pthread -Wall -std=c99
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h>
struct {
char buf[2];
bool cc1, cc2;
} *production = NULL;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_producter = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_customer = PTHREAD_COND_INITIALIZER;
void *producter(void *argv)
{
while(1) {
pthread_mutex_lock(&mutex);
if(!production) {
production = malloc(sizeof(*production));
strcpy(production->buf, "a");
} else {
while(production->cc1 || production->cc2)
pthread_cond_wait(&cond_customer, &mutex);
char c = production->buf[0] + 1;
production->buf[0] = c > 'z' ? 'a' : c;
}
production->cc1 = production->cc2 = true;
pthread_cond_signal(&cond_producter);
pthread_mutex_unlock(&mutex);
}
}
void *customer1(void *argv)
{
while(1) {
pthread_mutex_lock(&mutex);
while(!production || !production->cc1)
pthread_cond_wait(&cond_producter, &mutex);
printf("custom 1: %s\n", production->buf);
production->cc1 = false;
if(!production->cc2)
pthread_cond_signal(&cond_customer);
else
pthread_cond_signal(&cond_producter);
pthread_mutex_unlock(&mutex);
}
}
void *customer2(void *argv)
{
while(1) {
pthread_mutex_lock(&mutex);
while(!production || !production->cc2)
pthread_cond_wait(&cond_producter, &mutex);
printf("custom 2: %s\n", production->buf);
production->cc2 = false;
if(!production->cc1)
pthread_cond_signal(&cond_customer);
else
pthread_cond_signal(&cond_producter);
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, NULL, customer1, NULL);
pthread_create(&tid, NULL, customer2, NULL);
pthread_create(&tid, NULL, producter, NULL);
pthread_join(tid, NULL);
free(production);
return 0;
}
#6
程序中的三处等待条件变量的地方可以不用while循环的,只用if判断就行了。
#7
是应该用while判断,因为有可能发送虚假唤醒:期待的条件尚不成立的唤醒。
详见 UNIX网络编程 卷2:进程间通信。135页(中文翻译版)。
#8
以前还真没注意,受教了啊