生产者消费者模型如下:
程序如下:
1 #include <unistd.h> 2 #include <sys/types.h> 3 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <errno.h> 7 #include <string.h> 8 9 #include <pthread.h> 10 11 int g_Count = 0; 12 13 int nNum, nLoop; 14 15 //定义锁 16 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 17 18 //定义条件并初始化 19 pthread_cond_t my_condition=PTHREAD_COND_INITIALIZER; 20 21 #define CUSTOM_COUNT 2 22 #define PRODUCT_COUNT 4 23 24 25 // int pthread_mutex_lock(pthread_mutex_t *mutex); 26 // int pthread_mutex_trylock(pthread_mutex_t *mutex); 27 // int pthread_mutex_unlock(pthread_mutex_t *mutex); 28 29 /* 30 int pthread_cond_timedwait(pthread_cond_t *restrict cond, 31 pthread_mutex_t *restrict mutex, 32 const struct timespec *restrict abstime); 33 int pthread_cond_wait(pthread_cond_t *restrict cond, 34 pthread_mutex_t *restrict mutex); 35 */ 36 37 //posix 线程库的函数 线程库 38 void *consume(void* arg) 39 { 40 41 int inum = 0; 42 inum = (int)arg; 43 while(1) 44 { 45 pthread_mutex_lock(&mutex); 46 printf("consum:%d ", inum); 47 while (g_Count == 0) //while 醒来以后需要重新判断 条件g_Count是否满足,如果不满足,再次wait 48 { 49 printf("consum:%d 开始等待 ", inum); 50 pthread_cond_wait(&my_condition, &mutex); //api做了三件事情 //pthread_cond_wait假醒 51 printf("consum:%d 醒来 ", inum); 52 } 53 54 printf("consum:%d 消费产品begin ", inum); 55 g_Count--; //消费产品 56 printf("consum:%d 消费产品end ", inum); 57 58 pthread_mutex_unlock(&mutex); 59 60 sleep(1); 61 } 62 63 pthread_exit(0); 64 65 } 66 67 //生产者线程 68 // 69 void *produce(void* arg) 70 { 71 int inum = 0; 72 inum = (int)arg; 73 74 while(1) 75 { 76 77 /* 78 //因为是很多生产者调用produce,要保护全局变量g_Count,所以加锁 79 pthread_mutex_lock(&mutex); 80 if (g_Count > 20) 81 { 82 printf("produce:%d 产品太多,需要控制,休眠 ", inum); 83 pthread_mutex_unlock(&mutex); 84 sleep(1); 85 continue; 86 } 87 else 88 { 89 pthread_mutex_unlock(&mutex); 90 } 91 */ 92 93 pthread_mutex_lock(&mutex); 94 printf("产品数量:%d ", g_Count); 95 printf("produce:%d 生产产品begin ", inum); 96 g_Count++; 97 //只要我生产出一个产品,就告诉消费者去消费 98 printf("produce:%d 生产产品end ", inum); 99 100 printf("produce:%d 发条件signal begin ", inum); 101 pthread_cond_signal(&my_condition); //通知,在条件上等待的线程 102 printf("produce:%d 发条件signal end ", inum); 103 104 pthread_mutex_unlock(&mutex); 105 sleep(1); 106 } 107 108 pthread_exit(0); 109 110 } 111 112 //结论:return arg 和 pthread_exit()的结果都可以让pthread_join 接过来 113 int main() 114 { 115 int i =0; 116 pthread_t tidArray[CUSTOM_COUNT+PRODUCT_COUNT+10]; 117 118 //创建消费者线程 119 for (i=0; i<CUSTOM_COUNT; i++) 120 { 121 pthread_create(&tidArray[i], NULL, consume, (void *)i); 122 } 123 124 sleep(1); 125 //创建生产线程 126 for (i=0; i<PRODUCT_COUNT; i++) 127 { 128 pthread_create(&tidArray[i+CUSTOM_COUNT], NULL, produce, (void*)i); 129 } 130 131 132 133 for (i=0; i<CUSTOM_COUNT+PRODUCT_COUNT; i++) 134 { 135 pthread_join(tidArray[i], NULL); //等待线程结束。。。 136 } 137 138 139 printf("进程也要结束1233 "); 140 141 return 0; 142 }
执行结果如下:
条件等待模型如下:
多线程访问共享内存,通过信号量同步:不同进程中的线程无法进行同步与互斥
1 #include <sys/types.h> 2 #include <unistd.h> 3 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <string.h> 7 8 #include <signal.h> 9 #include <errno.h> 10 #include <signal.h> 11 #include <sys/wait.h> 12 13 #include "myipc_sem.h" 14 #include "myipc_shm.h" 15 16 #include <pthread.h> 17 18 int g_key = 0x3333; 19 20 void TestFunc(int loopnum) 21 { 22 printf("loopnum:%d ", loopnum); 23 24 int ncount = 0; 25 int ret = 0; 26 int shmhdl = 0; 27 int *addr = NULL; 28 29 int semid = 0; 30 sem_open(g_key, &semid); 31 32 33 sem_p(semid); //临界区开始 34 // 35 ret = IPC_CreatShm(".", 0, &shmhdl); 36 37 ret =IPC_MapShm(shmhdl, (void **)&addr); 38 *((int *)addr) = *((int *)addr) + 1; 39 ncount = *((int *)addr); 40 printf("ncount:%d ", ncount); 41 //addr[0] = addr[0] +1; 42 ret =IPC_UnMapShm(addr); 43 //sleep(2); 44 45 sem_v(semid); //临界区开始 46 // 47 printf("进程正常退出:%d ", getpid()); 48 } 49 50 51 52 //posix 线程库的函数 线程库 53 void *thread_routine(void* arg) 54 { 55 printf("thread_routine start "); 56 TestFunc(1); 57 pthread_exit(0); 58 59 } 60 61 int main(void ) 62 { 63 int res; 64 int procnum=10; 65 int loopnum = 100; 66 67 pthread_t tidArray[200]; 68 69 70 int i=0,j = 0; 71 72 printf("请输入要创建子进程的个数 : "); 73 scanf("%d", &procnum); 74 75 printf("请输入让每个子进程测试多少次 : "); 76 scanf("%d", &loopnum); 77 78 //共享内存创建 79 int ret = 0; 80 int shmhdl = 0; 81 ret = IPC_CreatShm(".", sizeof(int), &shmhdl); 82 if (ret != 0) 83 { 84 printf("func IPC_CreatShm() err:%d ", ret); 85 return ret; 86 } 87 88 89 //信号量的创建 90 int semid = 0; 91 ret = sem_creat(g_key, &semid); 92 if (ret != 0) 93 { 94 printf("func sem_creat() err:%d,重新按照open打开信号量 ", ret); 95 if (ret == SEMERR_EEXIST) 96 { 97 ret = sem_open(g_key, &semid); 98 if (ret != 0) 99 { 100 printf("按照打开的方式,重新获取sem失败:%d ", ret); 101 return ret; 102 } 103 } 104 else 105 { 106 return ret; 107 } 108 109 } 110 111 int val = 0; 112 ret = sem_getval(semid, &val); 113 if (ret != 0 ) 114 { 115 printf("func sem_getval() err:%d ", ret); 116 return ret; 117 } 118 printf("sem val:%d ", val); 119 getchar(); 120 121 for (i=0; i<procnum; i++) 122 { 123 124 //tmp.numId = i; //这说明 线程函数在使用了一个不断变化的内存空间。。。。 125 pthread_create(&tidArray[i], NULL, thread_routine, NULL); 126 } 127 128 for (i=0; i<procnum; i++) 129 { 130 pthread_join(tidArray[i], NULL); //等待线程结束。。。 131 } 132 133 134 printf("父进程退出 hello... "); 135 return 0; 136 }
多线程访问共享内存,通过线程锁实现:
1 #include <sys/types.h> 2 #include <unistd.h> 3 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <string.h> 7 8 #include <signal.h> 9 #include <errno.h> 10 #include <signal.h> 11 #include <sys/wait.h> 12 13 #include "myipc_sem.h" 14 #include "myipc_shm.h" 15 16 #include <pthread.h> 17 18 pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER; 19 20 int g_key = 0x3333; 21 22 void TestFunc(int loopnum) 23 { 24 printf("loopnum:%d ", loopnum); 25 26 int ncount = 0; 27 int ret = 0; 28 int shmhdl = 0; 29 int *addr = NULL; 30 31 int semid = 0; 32 sem_open(g_key, &semid); 33 34 35 sem_p(semid); //临界区开始 36 // 37 ret = IPC_CreatShm(".", 0, &shmhdl); 38 39 ret =IPC_MapShm(shmhdl, (void **)&addr); 40 *((int *)addr) = *((int *)addr) + 1; 41 ncount = *((int *)addr); 42 printf("ncount:%d ", ncount); 43 //addr[0] = addr[0] +1; 44 ret =IPC_UnMapShm(addr); 45 //sleep(2); 46 47 sem_v(semid); //临界区开始 48 // 49 printf("进程正常退出:%d ", getpid()); 50 } 51 52 void TestFunc_threadMutex(int loopnum) 53 { 54 printf("loopnum:%d ", loopnum); 55 56 int ncount = 0; 57 int ret = 0; 58 int shmhdl = 0; 59 int *addr = NULL; 60 61 int semid = 0; 62 sem_open(g_key, &semid); 63 64 65 //sem_p(semid); //临界区开始 66 pthread_mutex_lock(&mymutex); 67 // 68 ret = IPC_CreatShm(".", 0, &shmhdl); 69 70 ret =IPC_MapShm(shmhdl, (void **)&addr); 71 *((int *)addr) = *((int *)addr) + 1; 72 ncount = *((int *)addr); 73 printf("ncount:%d ", ncount); 74 //addr[0] = addr[0] +1; 75 ret =IPC_UnMapShm(addr); 76 //sleep(2); 77 78 //sem_v(semid); //临界区开始 79 pthread_mutex_unlock(&mymutex); 80 // 81 printf("进程正常退出:%d ", getpid()); 82 } 83 84 85 86 87 //posix 线程库的函数 线程库 88 void *thread_routine(void* arg) 89 { 90 printf("thread_routine start "); 91 //TestFunc(1); 92 TestFunc_threadMutex(1); 93 pthread_exit(0); 94 95 } 96 97 int main(void ) 98 { 99 int res; 100 int procnum=10; 101 int loopnum = 100; 102 103 pthread_t tidArray[1024*10]; 104 105 106 int i=0,j = 0; 107 108 printf("请输入要创建子进程的个数 : "); 109 scanf("%d", &procnum); 110 111 printf("请输入让每个子进程测试多少次 : "); 112 scanf("%d", &loopnum); 113 114 //共享内存创建 115 int ret = 0; 116 int shmhdl = 0; 117 ret = IPC_CreatShm(".", sizeof(int), &shmhdl); 118 if (ret != 0) 119 { 120 printf("func IPC_CreatShm() err:%d ", ret); 121 return ret; 122 } 123 124 125 //信号量的创建 126 int semid = 0; 127 ret = sem_creat(g_key, &semid); 128 if (ret != 0) 129 { 130 printf("func sem_creat() err:%d,重新按照open打开信号量 ", ret); 131 if (ret == SEMERR_EEXIST) 132 { 133 ret = sem_open(g_key, &semid); 134 if (ret != 0) 135 { 136 printf("按照打开的方式,重新获取sem失败:%d ", ret); 137 return ret; 138 } 139 } 140 else 141 { 142 return ret; 143 } 144 145 } 146 147 int val = 0; 148 ret = sem_getval(semid, &val); 149 if (ret != 0 ) 150 { 151 printf("func sem_getval() err:%d ", ret); 152 return ret; 153 } 154 printf("sem val:%d ", val); 155 getchar(); 156 157 for (i=0; i<procnum; i++) 158 { 159 160 //tmp.numId = i; //这说明 线程函数在使用了一个不断变化的内存空间。。。。 161 pthread_create(&tidArray[i], NULL, thread_routine, NULL); 162 } 163 164 for (i=0; i<procnum; i++) 165 { 166 pthread_join(tidArray[i], NULL); //等待线程结束。。。 167 } 168 169 170 printf("父进程退出 hello... "); 171 return 0; 172 }
服务器多进程模型、共享内存、信号量:
信号量封装:
1 #include <unistd.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <fcntl.h> 5 #include <sys/mman.h> 6 #include <sys/ipc.h> 7 #include <sys/shm.h> 8 #include <sys/sem.h> 9 10 #include <stdlib.h> 11 #include <stdio.h> 12 #include <errno.h> 13 #include <string.h> 14 15 #include <sys/ipc.h> 16 #include <sys/sem.h> 17 #include "myipc_sem.h" 18 19 20 union semun { 21 int val; /* Value for SETVAL */ 22 struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ 23 unsigned short *array; /* Array for GETALL, SETALL */ 24 struct seminfo *__buf; /* Buffer for IPC_INFO 25 (Linux specific) */ 26 }; 27 28 //@返回值 0 正确 其他错误 29 int sem_creat(int key, int *semid) 30 { 31 int ret = 0; 32 //int tmpsemid = 0; 33 34 if (semid == NULL) 35 { 36 ret = SEMERR_PARAM; 37 printf("func sem_creat() err:%d ", ret); 38 return ret; 39 } 40 ret = semget(key, 1, 0666| IPC_CREAT | IPC_EXCL); 41 if (ret == -1) 42 { 43 ret = errno; 44 //perror("semget"); 45 if (errno == EEXIST) 46 { 47 ret = SEMERR_EEXIST; 48 printf("func sem_creat() 检测到信号量集已经存在:%d ", ret); 49 return ret; 50 } 51 } 52 *semid = ret; 53 54 ret = sem_setval(*semid, 1); 55 if (ret != 0) 56 { 57 printf("func sem_setval() err:%d ", ret); 58 return ret; 59 } 60 ret = 0; 61 return ret; 62 } 63 64 int sem_open(int key, int *semid) 65 { 66 int ret = 0; 67 68 if (semid == NULL) 69 { 70 ret = SEMERR_PARAM; 71 printf("func sem_open() err:%d ", ret); 72 return ret; 73 } 74 75 ret = semget(key, 0, 0); 76 if (ret == -1) 77 { 78 ret = errno; 79 printf("func sem_open() 失败:%d ", ret); 80 return ret; 81 } 82 *semid = ret; 83 ret = 0; 84 return ret; 85 } 86 87 int sem_setval(int semid, int val) 88 { 89 int ret = 0; 90 union semun su; 91 su.val = val; 92 ret = semctl(semid, 0, SETVAL, su); 93 return ret; 94 } 95 96 /* 97 int sem_getval(int semid, int *val) 98 { 99 int ret = 0; 100 int tmpval; 101 if (val == NULL) 102 { 103 ret = SEMERR_PARAM; 104 printf("func sem_getval() err:%d ", ret); 105 return ret; 106 } 107 union semun su; 108 tmpval = su.val ; 109 ret = semctl(semid, 0, GETVAL, su); 110 *val = tmpval ; 111 printf("val:%d ", tmpval); 112 return ret; 113 } 114 */ 115 int sem_getval(int semid, int *myval) 116 { 117 int ret = 0; 118 int val; 119 union semun su; 120 val = su.val ; 121 //信号量 计数值 122 ret = semctl(semid, 0, GETVAL, su); 123 //printf("val:%d ", val); 124 125 *myval = ret; 126 ret = 0; 127 return ret; 128 } 129 130 //信号量p操作时候,需要传递好几个信息给linux内核 131 //所以linux内核定义了一个结构 132 //我要操作信号量集的下标 0 133 //我要执行什么操作 -1 +1 134 //我按照什么策略执行操作 0 UNDO NOWAITing 135 int sem_p(int semid) 136 { 137 struct sembuf buf = {0, -1, 0}; 138 int ret = 0; 139 ret = semop(semid, &buf, 1); 140 return ret; 141 } 142 143 int sem_v(int semid) 144 { 145 struct sembuf buf = {0, 1, 0}; 146 int ret = 0; 147 ret = semop(semid, &buf, 1); 148 return ret; 149 } 150 151 152 /* 153 int main() 154 { 155 156 //IPC_CREAT and IPC_EXCL a 157 int semid; 158 semid = sem_creat(0x1111); 159 //sem_setval(semid, 1); 160 //sem_getval(semid); 161 162 163 int pid = 0; 164 pid = fork(); 165 166 167 //sem_p(semid); 168 int i=0; 169 // printf("i:%d pid:%d ", i++, getpid()); 170 // sleep(3); 171 // printf("i:%d pid:%d ", i++, getpid()); 172 173 //sem_v(semid); 174 175 176 177 return 0; 178 } 179 */
共享内存封装:
1 #define _OS_LINUX_ 2 3 #if defined _OS_LINUX_ 4 #include <stdio.h> 5 #include <errno.h> 6 #include <unistd.h> 7 #include <memory.h> 8 #include <sys/ipc.h> 9 #include <sys/shm.h> 10 #include <sys/sem.h> 11 #include <sys/msg.h> 12 #include "myipc_shm.h" 13 14 #endif 15 16 int shmflag = 0; 17 int shmkey; 18 19 /*********************************************************************** 20 功能描述: 创建共享内存 21 参数说明: shmname [in] 是共享内存名,系统中唯一标志 22 shmsize [in] 是要创建的共享内存的大小; 23 shmhdl [out] 共享内存的句柄. 24 返回值: 返回0函数执行成功;非0返回错误码 25 ************************************************************************/ 26 int IPC_CreatShm(char *shmseedfile, int shmsize, int *shmhdl) 27 { 28 if(shmflag == 0) //判断接口中共享内存key是否已经存在 29 { 30 shmkey = ftok(shmseedfile, 'c'); 31 if (shmkey == -1) 32 { 33 perror("ftok"); 34 return -1; 35 } 36 37 shmflag = 1; 38 } 39 40 //创建共享内存 41 *shmhdl = shmget(shmkey,shmsize,IPC_CREAT|0666); 42 if (*shmhdl == -1) //创建失败 43 return -2; 44 return 0; 45 46 } 47 /*********************************************************************** 48 功能描述: 关联共享内存 49 参数说明: shmhdl [in] 共享的句柄 50 mapaddr [out] 共享内存首地址 51 返回值: 返回0函数执行成功;非0返回错误码 52 ************************************************************************/ 53 int 54 IPC_MapShm(int shmhdl, void **mapaddr) 55 { 56 void *tempptr = NULL; 57 58 //连接共享内存 59 tempptr = (void *)shmat(shmhdl,0,SHM_RND); 60 if ((int)tempptr == -1) //共享内存连接失败 61 return -1; 62 *mapaddr = tempptr; //导出共享内存首指针 63 64 return 0; 65 } 66 /*********************************************************************** 67 功能描述: 取消共享内存关联 68 参数说明: unmapaddr [in] 共享内存首地址 69 返回值: 返回0函数执行成功;非0返回错误码 70 ************************************************************************/ 71 int IPC_UnMapShm(void *unmapaddr) 72 { 73 int rv; 74 //取消连接共享内存 75 rv = shmdt((char *)unmapaddr); 76 if (rv == -1) //取消连接失败 77 return -1; 78 79 return 0; 80 } 81 /*********************************************************************** 82 功能描述: 删除共享内存 83 参数说明: shmhdl [in] 共享的句柄 84 返回值: 返回0函数执行成功;非0返回错误码 85 ************************************************************************/ 86 int IPC_DelShm(int shmhdl) 87 { 88 int rv; 89 //删除共享内存 90 rv = shmctl(shmhdl,IPC_RMID,NULL); 91 if(rv < 0) //删除共享内存失败 92 return -1; 93 return 0; 94 }
客户端:
1 #include <unistd.h> 2 #include <sys/types.h> 3 //#include <sys/socket.h> 4 //#include <netinet/in.h> 5 //#include <arpa/inet.h> 6 #include <signal.h> 7 #include <sys/wait.h> 8 //#include "sckutil.h" 9 10 #include <stdlib.h> 11 #include <stdio.h> 12 #include <errno.h> 13 #include <string.h> 14 15 #include "commsocket.h" 16 17 void handle(int signum) 18 { 19 int pid = 0; 20 printf("recv signum:%d ", signum); 21 22 //避免僵尸进程 23 while ((pid = waitpid(-1, NULL, WNOHANG) ) > 0) 24 { 25 printf("退出子进程pid%d ", pid); 26 fflush(stdout); 27 } 28 } 29 30 31 32 int main() 33 { 34 int ret = 0; 35 void *handle = NULL; 36 //void handle = NULL; 37 int connfd; 38 int i = 0, j = 0; 39 40 signal(SIGCHLD, handle); 41 signal(SIGPIPE, SIG_IGN); //防止 sokcet破裂 42 43 int procnum=10; 44 int loopnum = 100; 45 46 pthread_t tidArray[1024*2]; 47 48 49 50 printf("请输入要创建子进程的个数 : "); 51 scanf("%d", &procnum); 52 53 printf("请输入让每个子进程测试多少次 : "); 54 scanf("%d", &loopnum); 55 56 57 unsigned char *data = (unsigned char *)"aaaaaafffffffffffssssss"; 58 int datalen = 10; 59 60 unsigned char out[1024]; 61 int outlen = 1024; 62 //客户端环境初始化 63 64 ret = sckCliet_init(&handle, 15, 5, 5, 10); 65 66 for (i=0; i<procnum; i++) 67 { 68 int pid = fork(); 69 if (pid == 0) 70 { 71 ret = sckCliet_getconn(handle, "127.0.0.1", 8001, &connfd); 72 for (j=0; j<loopnum; j++) 73 { 74 //客户端发送报文 75 ret = sckClient_send(handle, connfd, data, datalen); 76 if (ret != 0) 77 { 78 if (ret == Sck_ErrTimeOut) 79 { 80 continue; 81 } 82 break; 83 } 84 //printf("ccccccc "); 85 //客户端端接受报文 86 ret = sckClient_rev(handle, connfd, out, &outlen); //10 87 if (ret != 0) 88 { 89 if (ret == Sck_ErrTimeOut) 90 { 91 break; 92 } 93 break; 94 } 95 out[outlen] = '