0
点赞
收藏
分享

微信扫一扫

9.20号作业实现钟表

一天清晨 2023-09-21 阅读 31
tcp/ip

目录

1--多线程的优点

2--进程和线程的差异

3--线程创建

4--线程使用

5--线程安全问题

6--互斥量

7--信号量

8--线程销毁

9--多线程并发聊天程序

9-1--服务器端

9-2--客户端

9-3--测试结果


1--多线程的优点

2--进程和线程的差异

3--线程创建

#include <pthread.h>
int pthread_create(pthread_t* restrict thread, const pthread_attr_t* restrict attr, void* (* start_routine)(void*), void* restrict arg);
// 成功时返回 0,失败时返回其他值
// thread 表示保存新创建线程 ID 的变量地址值
// attr 表示用于传递线程属性的参数,传递 NULL 时表示创建默认属性的线程
// start_routine 表示线程的入口函数
// arg 表示传递给线程入口函数的参数
// gcc thread1.c -o thread1 -lpthread
// ./thread1

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void* thread_main(void* arg){ // 线程入口函数
    int i;
    int cnt = *((int*)arg);
    for(i = 0; i < cnt; i++){
        sleep(1);
        puts("running thread");
    }
    return NULL;
}

int main(int argc, char* argv[]){
    pthread_t t_id;
    int thread_param = 5;
    if(pthread_create(&t_id, NULL, thread_main, (void*)&thread_param) != 0){ // 创建线程
        puts("pthread_create() error");
        return -1;
    }
    sleep(10);
    puts("end of main");
    return 0;
}

4--线程使用

#include <pthread.h>
int pthread_join(pthread_t thread, void** status);
// 成功时返回0,失败时返回其他值
// thread 表示线程ID,只有该线程终止后才会从函数返回
// status 表示保存线程返回值的指针变量地址值 
// gcc thread2.c -o thread2 -lpthread
// ./thread2

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

void* thread_main(void *arg){
    int i;
    int cnt = *((int*)arg);
    char* msg = (char*)malloc(sizeof(char)*50);
    strcpy(msg, "Hello, I'm thread~ \n");

    for(i = 0; i < cnt; i++){
        sleep(1);
        puts("running thread");
    }
    return (void*)msg;
}

int main(int argc, char* argv[]){
    pthread_t t_id;
    int thread_param = 5;
    void* thr_ret;

    // 创建线程
    if(pthread_create(&t_id, NULL, thread_main, (void*)&thread_param) != 0){
        puts("pthread_create() error");
        return -1;
    }
    // 阻塞,等待线程返回
    if(pthread_join(t_id, &thr_ret) != 0){
        puts("pthread_join() error");
        return -1;
    }

    // 打印线程返回值
    printf("Thread return message: %s \n", (char*)thr_ret);
    free(thr_ret);
    return 0;
}

5--线程安全问题

// gcc thread4.c -D_REENTRANT -o thread4 -lpthread
// ./thread4

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define NUM_THREAD 100

long long num = 0;

void* thread_inc(void* arg){
    int i;
    for(i = 0; i < 50000000; i++){
        num += 1;
    }
    return 0;
}

void* thread_des(void* arg){
    int i;
    for(i = 0; i < 50000000; i++){
        num -= 1;
    }
    return 0;
}

int main(int argc, char* argv[]){
    pthread_t thread_id[NUM_THREAD];
    int i;

    printf("sizeof long long: %ld \n", sizeof(long long));
    for(i = 0; i < NUM_THREAD; i++){
        // 各创建50个线程,分别执行对全局变量 num 的加减操作
        if(i%2){
            pthread_create(&(thread_id[i]), NULL, thread_inc, NULL);
        }
        else{
            pthread_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);
    return 0;
}

6--互斥量

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr);
int pthread_mutex_destroy(pthread_mutex_t* mutex);
// 成功时返回 0,失败时返回其他值
// mutex 表示创建和销毁互斥量时传递保存和销毁互斥量的变量地址值
// attr 传递即将创建的互斥量属性,没有特别需要指定的属性时传递 NULL

int pthread_mutex_lock(pthread_mutex_t* mutex); // 上锁
int pthread_mutex_unlock(pthread_mutex_t* mutex); // 解锁
// 成功时返回 0,失败时返回其他值

pthread_mutex_t mutex;
pthread_mutex_lock(&mutex);
// 临界区开始
// ...
// 临界区结束
pthread_mutex_unlock(&mutex);

7--信号量

#include <semaphore.h>
int sem_init(sem_t* sem, int pshared, unsigned int value);
int sem_destroy(sem_t* sem);
// 成功时返回 0,失败时返回其他值
// sem 表示信号量的变量地址值
// pshared 传递其他值时,创建可由多个进程共享的信号量;传递 0 时,创建只允许一个进程内部使用的信号量
// value 表示指定新创建的信号量的初始值

int sem_post(sem_t* sem); // 信号量增加1
int sem_wait(sem_t* sem); // 信号量减少1
// 成功时返回 0,失败时返回其他值

sem_wait(&sem); // 信号量变为0
// 临界区的开始
// ...
// 临界区的结束
sem_post(&sem); // 信号量变为1

8--线程销毁

9--多线程并发聊天程序

9-1--服务器端

// gcc chat_server.c -D_REENTRANT -o chat_server -lpthread
// ./chat_server 9190

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>

#define BUF_SIZE 100
#define MAX_CLNT 256

int clnt_cnt = 0;
int clnt_socks[MAX_CLNT];
pthread_mutex_t mutx;

void send_msg(char* msg, int len){
    int i;
    pthread_mutex_lock(&mutx);
    for(i = 0; i < clnt_cnt; i++){
        write(clnt_socks[i], msg, len);
    }
    pthread_mutex_unlock(&mutx);
}

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++){
        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 error_handling(char *msg){
    fputs(msg, stderr);
    fputc('\n', stderr);
    exit(1);
}

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;
}

9-2--客户端

// gcc chat_client.c -D_REENTRANT -o chat_client -lpthread
// ./chat_client 127.0.0.1 9190 Yoon

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>

#define BUF_SIZE 100
#define NAME_SIZE 20

char name[NAME_SIZE] = "[DEFAULT]";
char msg[BUF_SIZE];

void* send_msg(void* arg){
    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){
    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);
}

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;
}

9-3--测试结果

举报

相关推荐

9.20 作业

js实现动态钟表案例

3.29号作业

9.18号作业

9.14号作业

6月15号作业

0 条评论