一.实验目的
(1) 理解线程和进程的联系和区别;
(2) 掌握Linux下和Windows下创建线程的方法;
(3) 掌握Linux下和Windows下线程同步的方法;
(4) 使用多线程机制实现Linux下和Windows下服务器编程。
二.实验内容
(1)Linux下的线程同步
(1.1)编程使用互斥量实现线程同步;
(1.2)编程使用信号量实现线程同步,要求实现以下功能:“线程A从用户输入得到值后存入全局变量num,此时线程B将取走该值并累加。该过程共进行5次,完成后输出总和并退出程序”;
(1.3) 在(1.2)的基础上增加一个线程,用于求和之后计算所有数的平均值。
(1.4)用多线程并发方式实现一个群聊程序,包括服务器端和客户端。
(1.5)利用多线程技术实现回声服务器端,但要让所有线程共享保存客户端消息的内存空间(char数组)。
(2)Windows下的线程同步
(2.1)编程使用临界区对象实现线程同步;
(2.2)编程使用互斥量实现线程同步;
(2.3)编程使用信号量实现线程同步,要求实现以下功能:“线程A从用户输入得到值后存入全局变量num,此时线程B将取走该值并累加。该过程共进行5次,完成后输出总和并退出程序”;
(2.4)在第(2.3)的基础上增加一个线程,用于求和之后计算所有数的平均值。
(2.5)编程使用事件内核对象实现线程同步,要求实现以下功能:分别统计用户输入的字符串中’A’字符和非’A’字符的个数;
(2.6)用多线程并发方式实现一个群聊程序,包括服务器端和客户端。
三.实验过程
一、 Linux下的线程同步
1、P302mutex.c互斥量实现线程
实验代码:
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <pthread.h>#define NUM_THREAD 100void * thread_inc(void * arg);void * thread_des(void * arg);long long num=0;pthread_mutex_t mutex;int main(int argc, char *argv[]){pthread_t thread_id[NUM_THREAD];int i;pthread_mutex_init(&mutex, NULL);for(i=0; i<NUM_THREAD; i++){if(i%2)pthread_create(&(thread_id[i]), NULL, thread_inc, NULL);elsepthread_create(&(thread_id[i]), NULL, thread_des, NULL);}for(i=0; i<NUM_THREAD; i++)pthread_join(thread_id[i], NULL);printf(\"result: %lld \\n\", num);pthread_mutex_destroy(&mutex);return 0;}void * thread_inc(void * arg){int i;pthread_mutex_lock(&mutex);for(i=0; i<50000000; i++)num+=1;pthread_mutex_unlock(&mutex);return NULL;}void * thread_des(void * arg){int i;for(i=0; i<50000000; i++){pthread_mutex_lock(&mutex);num-=1;pthread_mutex_unlock(&mutex);}return NULL;}/*swyoon@com:~/tcpip$ gcc mutex.c -D_REENTRANT -o mutex -lpthreadswyoon@com:~/tcpip$ ./mutexresult: 0*/
结果:
2、P305semaphore.c 信号量实现线程同步
实验代码:
#include <stdio.h>#include <pthread.h>#include <semaphore.h>void * read(void * arg);void * accu(void * arg);static sem_t sem_one;static sem_t sem_two;static int num;int main(int argc, char *argv[]){pthread_t id_t1, id_t2;sem_init(&sem_one, 0, 0);sem_init(&sem_two, 0, 1);pthread_create(&id_t1, NULL, read, NULL);pthread_create(&id_t2, NULL, accu, NULL);pthread_join(id_t1, NULL);pthread_join(id_t2, NULL);sem_destroy(&sem_one);sem_destroy(&sem_two);return 0;}void * read(void * arg){int i;for(i=0; i<5; i++){fputs(\"Input num: \", stdout);sem_wait(&sem_two);scanf(\"%d\", &num);sem_post(&sem_one);}return NULL;}void * accu(void * arg){int sum=0, i;for(i=0; i<5; i++){sem_wait(&sem_one);sum+=num;sem_post(&sem_two);}printf(\"Result: %d \\n\", sum);return NULL;}
结果:
3、在P305semaphore.c的基础上增加一个线程,用于求和之后计算所有数的平均值。
#include <stdio.h>#include <pthread.h>#include <semaphore.h>void * read(void * arg);void * accu(void * arg);void * aver(void * arg);static sem_t sem_one;static sem_t sem_two;static sem_t sem_three;static int num;int main(int argc, char *argv[]){pthread_t id_t1, id_t2, id_t3;sem_init(&sem_one, 0, 0);sem_init(&sem_two, 0, 0);sem_init(&sem_three, 0, 1);pthread_create(&id_t1, NULL, read, NULL);pthread_create(&id_t2, NULL, accu, NULL);pthread_create(&id_t3, NULL, aver, NULL);pthread_join(id_t1, NULL);pthread_join(id_t2, NULL);pthread_join(id_t3, NULL);sem_destroy(&sem_one);sem_destroy(&sem_two);sem_destroy(&sem_three);return 0;}void * read(void * arg){int i;for(i=0; i<5; i++){fputs(\"Input num: \", stdout);sem_wait(&sem_three);scanf(\"%d\", &num);sem_post(&sem_one);}return NULL;}void * accu(void * arg){int sum = 0, i;for(i=0; i<5; i++){sem_wait(&sem_one);sum+=num;sem_post(&sem_two);}printf(\"Result: %d \\n\", sum);return NULL;}void * aver(void * arg){int sum = 0, i, ave = 0;for(i=0; i<5; i++){sem_wait(&sem_two);sum+=num;sem_post(&sem_three);}ave = sum / 5;printf(\"Average: %d \\n\", ave);return NULL;}
结果:
4、P307用多线程并发方式实现一个群聊程序,包括服务器端和客户端。
实验代码:
Chat_server.c:#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <arpa/inet.h>#include <sys/socket.h>#include <netinet/in.h>#include <pthread.h>#define BUF_SIZE 100#define MAX_CLNT 256void * handle_clnt(void * arg);void send_msg(char * msg, int len);void error_handling(char * msg);int clnt_cnt=0;int clnt_socks[MAX_CLNT];pthread_mutex_t mutx;int main(int argc, char *argv[]){int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;int clnt_adr_sz;pthread_t t_id;if(argc!=2) {printf(\"Usage : %s <port>\\n\", argv[0]);exit(1);}pthread_mutex_init(&mutx, NULL);serv_sock=socket(PF_INET, SOCK_STREAM, 0);memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);serv_adr.sin_port=htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr))==-1)error_handling(\"bind() error\");if(listen(serv_sock, 5)==-1)error_handling(\"listen() error\");while(1){clnt_adr_sz=sizeof(clnt_adr);clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr,&clnt_adr_sz);pthread_mutex_lock(&mutx);clnt_socks[clnt_cnt++]=clnt_sock;pthread_mutex_unlock(&mutx);pthread_create(&t_id, NULL, handle_clnt, (void*)&clnt_sock);pthread_detach(t_id);printf(\"Connected client IP: %s \\n\", inet_ntoa(clnt_adr.sin_addr));}close(serv_sock);return 0;}void * handle_clnt(void * arg){int clnt_sock=*((int*)arg);int str_len=0, i;char msg[BUF_SIZE];while((str_len=read(clnt_sock, msg, sizeof(msg)))!=0)send_msg(msg, str_len);pthread_mutex_lock(&mutx);for(i=0; i<clnt_cnt; i++) // remove disconnected client{if(clnt_sock==clnt_socks[i]){while(i++<clnt_cnt-1)clnt_socks[i]=clnt_socks[i+1];break;}}clnt_cnt--;pthread_mutex_unlock(&mutx);close(clnt_sock);return NULL;}void send_msg(char * msg, int len) // send to all{int i;pthread_mutex_lock(&mutx);for(i=0; i<clnt_cnt; i++)write(clnt_socks[i], msg, len);pthread_mutex_unlock(&mutx);}void error_handling(char * msg){fputs(msg, stderr);fputc(\'\\n\', stderr);exit(1);}Chat_client.c:#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <arpa/inet.h>#include <sys/socket.h>#include <pthread.h>#define BUF_SIZE 100#define NAME_SIZE 20void * send_msg(void * arg);void * recv_msg(void * arg);void error_handling(char * msg);char name[NAME_SIZE]=\"[DEFAULT]\";char msg[BUF_SIZE];int main(int argc, char *argv[]){int sock;struct sockaddr_in serv_addr;pthread_t snd_thread, rcv_thread;void * thread_return;if(argc!=4) {printf(\"Usage : %s <IP> <port> <name>\\n\", argv[0]);exit(1);}sprintf(name, \"[%s]\", argv[3]);sock=socket(PF_INET, SOCK_STREAM, 0);memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=inet_addr(argv[1]);serv_addr.sin_port=htons(atoi(argv[2]));if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1)error_handling(\"connect() error\");pthread_create(&snd_thread, NULL, send_msg, (void*)&sock);pthread_create(&rcv_thread, NULL, recv_msg, (void*)&sock);pthread_join(snd_thread, &thread_return);pthread_join(rcv_thread, &thread_return);close(sock);return 0;}void * send_msg(void * arg) // send thread main{int sock=*((int*)arg);char name_msg[NAME_SIZE+BUF_SIZE];while(1){fgets(msg, BUF_SIZE, stdin);if(!strcmp(msg,\"q\\n\")||!strcmp(msg,\"Q\\n\")){close(sock);exit(0);}sprintf(name_msg,\"%s %s\", name, msg);write(sock, name_msg, strlen(name_msg));}return NULL;}void * recv_msg(void * arg) // read thread main{int sock=*((int*)arg);char name_msg[NAME_SIZE+BUF_SIZE];int str_len;while(1){str_len=read(sock, name_msg, NAME_SIZE+BUF_SIZE-1);if(str_len==-1)return (void*)-1;name_msg[str_len]=0;fputs(name_msg, stdout);}return NULL;}void error_handling(char *msg){fputs(msg, stderr);fputc(\'\\n\', stderr);exit(1);}
结果:
5、P313习题7
实验代码:
Echo_server.c://echo_thrserv.c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#include <sys/select.h>#include <pthread.h>#define BUF_SIZE 100void * handle_clnt(void * arg);void error_handling(char *buf);char buf[BUF_SIZE];pthread_mutex_t mutx;int main(int argc, char *argv[]){int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;int clnt_adr_sz;pthread_t t_id;if(argc!=2) {printf(\"Usage : %s <port>\\n\", argv[0]);exit(1);}pthread_mutex_init(&mutx, NULL);serv_sock=socket(PF_INET, SOCK_STREAM, 0);memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);serv_adr.sin_port=htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr))==-1)error_handling(\"bind() error\");if(listen(serv_sock, 5)==-1)error_handling(\"listen() error\");while(1){clnt_adr_sz=sizeof(clnt_adr);clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr,&clnt_adr_sz);pthread_create(&t_id, NULL, handle_clnt, (void*)&clnt_sock);pthread_detach(t_id);printf(\"Connected client IP: %s \\n\", inet_ntoa(clnt_adr.sin_addr));}close(serv_sock);return 0;}void * handle_clnt(void * arg){int clnt_sock=*((int*)arg);int str_len=0;while(1){pthread_mutex_lock(&mutx);str_len=read(clnt_sock, buf, sizeof(buf));if(str_len<=0)break;elsewrite(clnt_sock, buf, str_len);pthread_mutex_unlock(&mutx);}close(clnt_sock);return NULL;}void error_handling(char *buf){fputs(buf, stderr);fputc(\'\\n\', stderr);exit(1);}Echo_client.c:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#define BUF_SIZE 1024void error_handling(char *message);int main(int argc, char *argv[]){int sock;char message[BUF_SIZE];int str_len;struct sockaddr_in serv_adr;if(argc!=3) {printf(\"Usage : %s <IP> <port>\\n\", argv[0]);exit(1);}sock=socket(PF_INET, SOCK_STREAM, 0);if(sock==-1)error_handling(\"socket() error\");memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=inet_addr(argv[1]);serv_adr.sin_port=htons(atoi(argv[2]));if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)error_handling(\"connect() error!\");elseputs(\"Connected...........\");while(1){fputs(\"Input message(Q to quit): \", stdout);fgets(message, BUF_SIZE, stdin);if(!strcmp(message,\"q\\n\") || !strcmp(message,\"Q\\n\"))break;write(sock, message, strlen(message));str_len=read(sock, message, BUF_SIZE-1);message[str_len]=0;printf(\"Message from server: %s\", message);}close(sock);return 0;}void error_handling(char *message){fputs(message, stderr);fputc(\'\\n\', stderr);exit(1);}
结果:
二、 Windows下的线程同步
6、P330临界区对象实现线程同步
实验代码:
#include <stdio.h>#include <windows.h>#include <process.h>#define NUM_THREAD 50unsigned WINAPI threadInc(void* arg);unsigned WINAPI threadDes(void* arg);long long num = 0;CRITICAL_SECTION cs;int main(int argc, char* argv[]){HANDLE tHandles[NUM_THREAD];int i;InitializeCriticalSection(&cs);for (i = 0; i < NUM_THREAD; i++){if (i % 2)tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL);elsetHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL);}WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE);DeleteCriticalSection(&cs);printf(\"result: %lld \\n\", num);return 0;}unsigned WINAPI threadInc(void* arg){int i;EnterCriticalSection(&cs);for (i = 0; i < 50000000; i++)num += 1;LeaveCriticalSection(&cs);return 0;}unsigned WINAPI threadDes(void* arg){int i;EnterCriticalSection(&cs);for (i = 0; i < 50000000; i++)num -= 1;LeaveCriticalSection(&cs);return 0;}
结果:
7、P333互斥量实现线程同步
实验代码:
#include <stdio.h>#include <windows.h>#include <process.h>#define NUM_THREAD 50unsigned WINAPI threadInc(void* arg);unsigned WINAPI threadDes(void* arg);long long num = 0;HANDLE hMutex;int main(int argc, char* argv[]){HANDLE tHandles[NUM_THREAD];int i;hMutex = CreateMutex(NULL, FALSE, NULL);for (i = 0; i < NUM_THREAD; i++){if (i % 2)tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL);elsetHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL);}WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE);CloseHandle(hMutex);printf(\"result: %lld \\n\", num);return 0;}unsigned WINAPI threadInc(void* arg){int i;WaitForSingleObject(hMutex, INFINITE);for (i = 0; i < 50000000; i++)num += 1;ReleaseMutex(hMutex);return 0;}unsigned WINAPI threadDes(void* arg){int i;WaitForSingleObject(hMutex, INFINITE);for (i = 0; i < 50000000; i++)num -= 1;ReleaseMutex(hMutex);return 0;}
结果:
8、P335-P336信号量实现线程同步
实验代码:
#include <stdio.h>#include <windows.h>#include <process.h>unsigned WINAPI Read(void* arg);unsigned WINAPI Accu(void* arg);static HANDLE semOne;static HANDLE semTwo;static int num;int main(int argc, char* argv[]){HANDLE hThread1, hThread2;semOne = CreateSemaphore(NULL, 0, 1, NULL);semTwo = CreateSemaphore(NULL, 1, 1, NULL);hThread1 = (HANDLE)_beginthreadex(NULL, 0, Read, NULL, 0, NULL);hThread2 = (HANDLE)_beginthreadex(NULL, 0, Accu, NULL, 0, NULL);WaitForSingleObject(hThread1, INFINITE);WaitForSingleObject(hThread2, INFINITE);CloseHandle(semOne);CloseHandle(semTwo);return 0;}unsigned WINAPI Read(void* arg){int i;for (i = 0; i < 5; i++){fputs(\"Input num: \", stdout);WaitForSingleObject(semTwo, INFINITE);scanf(\"%d\", &num);ReleaseSemaphore(semOne, 1, NULL);}return 0;}unsigned WINAPI Accu(void* arg){int sum = 0, i;for (i = 0; i < 5; i++){WaitForSingleObject(semOne, INFINITE);sum += num;ReleaseSemaphore(semTwo, 1, NULL);}printf(\"Result: %d \\n\", sum);return 0;}
结果:
9、在第8题的基础上增加一个线程,用于求和之后计算所有数的平均值。
#include <stdio.h>#include <windows.h>#include <process.h>unsigned WINAPI Read(void * arg);unsigned WINAPI Accu(void * arg);unsigned WINAPI Aver(void * arg);static HANDLE semOne;static HANDLE semTwo;static HANDLE semThree;static int num;int main(int argc, char *argv[]){HANDLE hThread1, hThread2, hThread3;semOne=CreateSemaphore(NULL, 0, 1, NULL);semTwo=CreateSemaphore(NULL, 0, 1, NULL);semThree=CreateSemaphore(NULL, 1, 1, NULL);hThread1=(HANDLE)_beginthreadex(NULL, 0, Read, NULL, 0, NULL);hThread2=(HANDLE)_beginthreadex(NULL, 0, Accu, NULL, 0, NULL);hThread3=(HANDLE)_beginthreadex(NULL, 0, Aver, NULL, 0, NULL);WaitForSingleObject(hThread1, INFINITE);WaitForSingleObject(hThread2, INFINITE);WaitForSingleObject(hThread3, INFINITE);CloseHandle(semOne);CloseHandle(semTwo);CloseHandle(semThree);return 0;}unsigned WINAPI Read(void * arg){int i;for(i=0; i<5; i++){fputs(\"Input num: \", stdout);WaitForSingleObject(semThree, INFINITE);scanf(\"%d\", &num);ReleaseSemaphore(semTwo, 1, NULL);}return 0;}unsigned WINAPI Accu(void * arg){int sum=0, i;for(i=0; i<5; i++){WaitForSingleObject(semTwo, INFINITE);sum+=num;ReleaseSemaphore(semOne, 1, NULL);}printf(\"Result: %d \\n\", sum);return 0;}unsigned WINAPI Aver(void * arg){int sum=0, ave = 0, i;for(i=0; i<5; i++){WaitForSingleObject(semOne, INFINITE);sum+=num;ReleaseSemaphore(semThree, 1, NULL);}ave = sum / 5;printf(\"Average: %d \\n\", ave);return 0;}
结果:
10、P337-P338事件内核对象实现线程同步
实验代码:
#include <stdio.h>#include <windows.h>#include <process.h>#define STR_LEN 100unsigned WINAPI NumberOfA(void* arg);unsigned WINAPI NumberOfOthers(void* arg);static char str[STR_LEN];static HANDLE hEvent;int main(int argc, char* argv[]){HANDLE hThread1, hThread2;hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);hThread1 = (HANDLE)_beginthreadex(NULL, 0, NumberOfA, NULL, 0, NULL);hThread2 = (HANDLE)_beginthreadex(NULL, 0, NumberOfOthers, NULL, 0, NULL);fputs(\"Input string: \", stdout);fgets(str, STR_LEN, stdin);SetEvent(hEvent);WaitForSingleObject(hThread1, INFINITE);WaitForSingleObject(hThread2, INFINITE);ResetEvent(hEvent);CloseHandle(hEvent);return 0;}unsigned WINAPI NumberOfA(void* arg){int i, cnt = 0;WaitForSingleObject(hEvent, INFINITE);for (i = 0; str[i] != 0; i++){if (str[i] == \'A\')cnt++;}printf(\"Num of A: %d \\n\", cnt);return 0;}unsigned WINAPI NumberOfOthers(void* arg){int i, cnt = 0;WaitForSingleObject(hEvent, INFINITE);for (i = 0; str[i] != 0; i++){if (str[i] != \'A\')cnt++;}printf(\"Num of others: %d \\n\", cnt - 1);return 0;}
结果:
11、P339用多线程并发方式实现一个群聊程序,包括服务器端和客户端。
实验代码:
Server.c:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <windows.h>#include <process.h>#define BUF_SIZE 100#define MAX_CLNT 256unsigned WINAPI HandleClnt(void* arg);void SendMsg(char* msg, int len);void ErrorHandling(char* msg);int clntCnt = 0;SOCKET clntSocks[MAX_CLNT];HANDLE hMutex;int main(int argc, char* argv[]){WSADATA wsaData;SOCKET hServSock, hClntSock;SOCKADDR_IN servAdr, clntAdr;int clntAdrSz;HANDLE hThread;if (argc != 2) {printf(\"Usage : %s <port>\\n\", argv[0]);exit(1);}if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)ErrorHandling(\"WSAStartup() error!\");hMutex = CreateMutex(NULL, FALSE, NULL);hServSock = socket(PF_INET, SOCK_STREAM, 0);memset(&servAdr, 0, sizeof(servAdr));servAdr.sin_family = AF_INET;servAdr.sin_addr.s_addr = htonl(INADDR_ANY);servAdr.sin_port = htons(atoi(argv[1]));if (bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)ErrorHandling(\"bind() error\");if (listen(hServSock, 5) == SOCKET_ERROR)ErrorHandling(\"listen() error\");while (1){clntAdrSz = sizeof(clntAdr);hClntSock = accept(hServSock, (SOCKADDR*)&clntAdr, &clntAdrSz);WaitForSingleObject(hMutex, INFINITE);clntSocks[clntCnt++] = hClntSock;ReleaseMutex(hMutex);hThread =(HANDLE)_beginthreadex(NULL, 0, HandleClnt, (void*)&hClntSock, 0, NULL);printf(\"Connected client IP: %s \\n\", inet_ntoa(clntAdr.sin_addr));}closesocket(hServSock);WSACleanup();return 0;}unsigned WINAPI HandleClnt(void* arg){SOCKET hClntSock = *((SOCKET*)arg);int strLen = 0, i;char msg[BUF_SIZE];while ((strLen = recv(hClntSock, msg, sizeof(msg), 0)) != 0)SendMsg(msg, strLen);WaitForSingleObject(hMutex, INFINITE);for (i = 0; i < clntCnt; i++) // remove disconnected client{if (hClntSock == clntSocks[i]){while (i++ < clntCnt - 1)clntSocks[i] = clntSocks[i + 1];break;}}clntCnt--;ReleaseMutex(hMutex);closesocket(hClntSock);return 0;}void SendMsg(char* msg, int len) // send to all{int i;WaitForSingleObject(hMutex, INFINITE);for (i = 0; i < clntCnt; i++)send(clntSocks[i], msg, len, 0);ReleaseMutex(hMutex);}void ErrorHandling(char* msg){fputs(msg, stderr);fputc(\'\\n\', stderr);exit(1);}Client.c:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <windows.h>#include <process.h>#define BUF_SIZE 100#define NAME_SIZE 20unsigned WINAPI SendMsg(void* arg);unsigned WINAPI RecvMsg(void* arg);void ErrorHandling(char* msg);char name[NAME_SIZE] = \"[DEFAULT]\";char msg[BUF_SIZE];int main(int argc, char* argv[]){WSADATA wsaData;SOCKET hSock;SOCKADDR_IN servAdr;HANDLE hSndThread, hRcvThread;if (argc != 4) {printf(\"Usage : %s <IP> <port> <name>\\n\", argv[0]);exit(1);}if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)ErrorHandling(\"WSAStartup() error!\");sprintf(name, \"[%s]\", argv[3]);hSock = socket(PF_INET, SOCK_STREAM, 0);memset(&servAdr, 0, sizeof(servAdr));servAdr.sin_family = AF_INET;servAdr.sin_addr.s_addr = inet_addr(argv[1]);servAdr.sin_port = htons(atoi(argv[2]));if (connect(hSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)ErrorHandling(\"connect() error\");hSndThread =(HANDLE)_beginthreadex(NULL, 0, SendMsg, (void*)&hSock, 0, NULL);hRcvThread =(HANDLE)_beginthreadex(NULL, 0, RecvMsg, (void*)&hSock, 0, NULL);WaitForSingleObject(hSndThread, INFINITE);WaitForSingleObject(hRcvThread, INFINITE);closesocket(hSock);WSACleanup();return 0;}unsigned WINAPI SendMsg(void* arg) // send thread main{SOCKET hSock = *((SOCKET*)arg);char nameMsg[NAME_SIZE + BUF_SIZE];while (1){fgets(msg, BUF_SIZE, stdin);if (!strcmp(msg, \"q\\n\") || !strcmp(msg, \"Q\\n\")){closesocket(hSock);exit(0);}sprintf(nameMsg, \"%s %s\", name, msg);send(hSock, nameMsg, strlen(nameMsg), 0);}return 0;}unsigned WINAPI RecvMsg(void* arg) // read thread main{int hSock = *((SOCKET*)arg);char nameMsg[NAME_SIZE + BUF_SIZE];int strLen;while (1){strLen = recv(hSock, nameMsg, NAME_SIZE + BUF_SIZE - 1, 0);if (strLen == -1)return -1;nameMsg[strLen] = 0;fputs(nameMsg, stdout);}return 0;}void ErrorHandling(char* msg){fputs(msg, stderr);fputc(\'\\n\', stderr);exit(1);}
结果:
12、P343习题3
实验代码:
#include <stdio.h>#include <windows.h>#include <process.h>unsigned WINAPI Read(void* arg);unsigned WINAPI Accu(void* arg);static HANDLE semOne;static HANDLE semTwo;static int num;int main(int argc, char* argv[]){HANDLE hThread1, hThread2;semOne = CreateSemaphore(NULL, 0, 1, NULL);semTwo = CreateSemaphore(NULL, 1, 1, NULL);hThread1 = (HANDLE)_beginthreadex(NULL, 0, Read, NULL, 0, NULL);hThread2 = (HANDLE)_beginthreadex(NULL, 0, Accu, NULL, 0, NULL);WaitForSingleObject(hThread1, INFINITE);WaitForSingleObject(hThread2, INFINITE);CloseHandle(semOne);CloseHandle(semTwo);return 0;}unsigned WINAPI Read(void* arg){int i, rdData;for (i = 0; i < 5; i++){fputs(\"Input num: \", stdout);scanf(\"%d\", &rdData);WaitForSingleObject(semTwo, INFINITE);num = rdData;ReleaseSemaphore(semOne, 1, NULL);}return 0;}unsigned WINAPI Accu(void* arg){int sum = 0, i;for (i = 0; i < 5; i++){WaitForSingleObject(semOne, INFINITE);sum += num;ReleaseSemaphore(semTwo, 1, NULL);}printf(\"Result: %d \\n\", sum);return 0;}
结果:
13、P343习题4
实验代码:
#include <stdio.h>#include <windows.h>#include <process.h>#define STR_LEN 100unsigned WINAPI NumberOfA(void* arg);unsigned WINAPI NumberOfOthers(void* arg);static char str[STR_LEN];static HANDLE hSema;int main(int argc, char* argv[]){HANDLE hThread1, hThread2;hSema = CreateSemaphore(NULL, 0, 2, NULL);hThread1 = (HANDLE)_beginthreadex(NULL, 0, NumberOfA, NULL, 0, NULL);hThread2 = (HANDLE)_beginthreadex(NULL, 0, NumberOfOthers, NULL, 0, NULL);fputs(\"Input string: \", stdout);fgets(str, STR_LEN, stdin);ReleaseSemaphore(hSema, 2, NULL);WaitForSingleObject(hThread1, INFINITE);WaitForSingleObject(hThread2, INFINITE);ResetEvent(hSema);CloseHandle(hSema);return 0;}unsigned WINAPI NumberOfA(void* arg){int i, cnt = 0;WaitForSingleObject(hSema, INFINITE);for (i = 0; str[i] != 0; i++){if (str[i] == \'A\')cnt++;}printf(\"Num of A: %d \\n\", cnt);return 0;}unsigned WINAPI NumberOfOthers(void* arg){int i, cnt = 0;WaitForSingleObject(hSema, INFINITE);for (i = 0; str[i] != 0; i++){if (str[i] != \'A\')cnt++;}printf(\"Num of others: %d \\n\", cnt - 1);return 0;}
结果: