针对线程中有阻塞函数情况下如何快速结束线程

发布时间 2023-04-19 15:28:23作者: bailinjun
不使用cancle线程时需要等待很长时间才能退出两个线程

#include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> #include <termios.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <errno.h> #include "signal.h" #include <pthread.h> #include <sys/select.h> #include <sys/stat.h> #include <linux/serial.h> #include <sys/ioctl.h> #define SERIAL1 "/dev/ttySTM1" /// dev/ttySTM0对应打印串口终端 #define SERIAL2 "/dev/ttySTM2" #define SERIAL3 "/dev/ttySTM3" #define PRONUM 16 // 串口使用协议的总数量 unsigned char gprotocolType[3][PRONUM]; unsigned char tempbits[3], tempstopbits[3], tempparity[3]; unsigned int tempbaud[3]; // 默认波特率为19200 int g_Sys_Status = 0; int gSerialFd1; int Serial_Cfg(unsigned char num, int baudrate, unsigned char parity, unsigned char data_bit, unsigned char stop_bit) { int fd; speed_t speed; struct termios tios; char device[20]; if (num == 1) { strcpy(device, SERIAL1); } else if (num == 2) { strcpy(device, SERIAL2); } fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK); // mylog(" fd= %d num=%d baud=%d databit=%d stop_bit=%d parity=%c\n",fd,num,baudrate,data_bit,stop_bit,parity); if (fd < 0) { printf("open error\n"); return -1; } #if 1 memset(&tios, 0, sizeof(struct termios)); #else struct termios old_tios; tcgetattr(fd, &old_tios); memcpy(&tios, &old_tios, sizeof(struct termios)); #endif switch (baudrate) { case 1200: speed = B1200; break; case 2400: speed = B2400; break; case 4800: speed = B4800; break; case 9600: speed = B9600; break; case 19200: speed = B19200; break; case 38400: speed = B38400; break; case 57600: speed = B57600; break; case 115200: speed = B115200; break; case 230400: speed = B230400; break; case 460800: speed = B460800; break; case 500000: speed = B500000; break; case 576000: speed = B576000; break; case 921600: speed = B921600; break; case 1000000: speed = B1000000; break; case 1152000: speed = B1152000; break; default: speed = B9600; printf("error baudrate\n"); } if ((cfsetispeed(&tios, speed) < 0) || (cfsetospeed(&tios, speed) < 0)) { close(fd); return -1; } tios.c_cflag |= (CREAD | CLOCAL); tios.c_cflag &= ~CSIZE; switch (data_bit) { case 5: tios.c_cflag |= CS5; break; case 6: tios.c_cflag |= CS6; break; case 7: tios.c_cflag |= CS7; break; case 8: default: tios.c_cflag |= CS8; break; } if (stop_bit == 1) tios.c_cflag &= ~CSTOPB; else tios.c_cflag |= CSTOPB; if (parity == 'N') { tios.c_cflag &= ~PARENB; } else if (parity == 'E') { tios.c_cflag |= PARENB; tios.c_cflag &= ~PARODD; } else { tios.c_cflag |= PARENB; tios.c_cflag |= PARODD; } tios.c_cflag &= ~HUPCL; tios.c_iflag &= ~INPCK; tios.c_iflag |= IGNBRK; tios.c_iflag &= ~ICRNL; tios.c_iflag &= ~IXON; tios.c_lflag &= ~IEXTEN; tios.c_lflag &= ~ECHOK; tios.c_lflag &= ~ECHOCTL; tios.c_lflag &= ~ECHOKE; tios.c_oflag &= ~ONLCR; tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); if (parity == 'N') { /* None */ tios.c_iflag &= ~INPCK; } else { tios.c_iflag |= INPCK; } tios.c_iflag &= ~(IXON | IXOFF | IXANY); tios.c_oflag &= ~OPOST; tios.c_cc[VMIN] = 0; tios.c_cc[VTIME] = 0; if (tcsetattr(fd, TCSANOW, &tios) < 0) { close(fd); return -1; } struct serial_rs485 rs485conf; ioctl(fd, TIOCGRS485, &rs485conf); rs485conf.flags |= SER_RS485_ENABLED; ioctl(fd, TIOCSRS485, &rs485conf); return fd; } void RTU_receive() { int fd; fd = gSerialFd1; fd_set fds; FD_ZERO(&fds); FD_SET(fd, &fds); struct timeval tv; tv.tv_sec = 60; tv.tv_usec = 0; while (1) { // printf("======================================\n"); int ret = select(fd + 1, &fds, NULL, NULL, &tv); if (ret == -1) { fprintf(stderr, "fail to select, error: %d, %s\n", errno, strerror(errno)); } else if (ret == 0) { fprintf(stderr, "select timeout\n"); } else { fprintf(stdout, "success to select\n"); // int result =read(); } if (g_Sys_Status == 4) { printf("===============\n"); break; } else { printf("===============g_Sys_Status == 2\n"); } } } void main() // int argc, int *argv { int i; int ret[PRONUM]; pthread_attr_t thread_attr; pthread_t thread_id; // struct sched_param thread_param[PRONUM]; unsigned char myNum[PRONUM]; int tempEnable[PRONUM]; if (1) { gSerialFd1 = Serial_Cfg(1, 19200, 'E', 8, 1); pthread_attr_init(&thread_attr); // thread_param[0].sched_priority = RUNNETWORK_THREAD_PRIO; // pthread_attr_setschedpolicy(&(thread_attr[0]), SCHED_FIFO); // pthread_attr_setschedparam(&(thread_attr[0]), &(thread_param[0])); ret[0] = pthread_create(&(thread_id), &(thread_attr), (void *)RTU_receive, NULL); if (ret[0] != 0) { printf("pthread_create error thread_param!\n"); // continue; } pthread_attr_destroy(&(thread_attr)); } char cmdbuf[20] = {0}; char *string; while (1) { printf("2input cmd:"); memset(cmdbuf, 0, 20 * sizeof(char)); string = fgets(cmdbuf, 20, stdin); // if (strcmp(cmdbuf, "2\n") == 0) { g_Sys_Status = 2; } else if (strcmp(cmdbuf, "4\n") == 0) { g_Sys_Status = 4; } else if (strcmp(cmdbuf, "6\n") == 0) { printf("RRRRRR= 6\n"); } printf("%s\n", string); if (g_Sys_Status == 4) // 停止状态下结束所有线程 { // pthread_cancel(thread_id); //使用cancle时快速退出线程 pthread_join(thread_id, NULL); break; } usleep(5000); } }

问题2:为何select一次之后就不能再次循环,再次进入select?

需要将tv时间再次赋值

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include "signal.h"
#include <pthread.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <linux/serial.h>
#include <sys/ioctl.h>

#define SERIAL1 "/dev/ttySTM1" /// dev/ttySTM0对应打印串口终端
#define SERIAL2 "/dev/ttySTM2"
#define SERIAL3 "/dev/ttySTM3"

#define PRONUM 16 // 串口使用协议的总数量
unsigned char gprotocolType[3][PRONUM];
unsigned char tempbits[3], tempstopbits[3], tempparity[3];
unsigned int tempbaud[3]; // 默认波特率为19200
int g_Sys_Status = 0;
int gSerialFd1;
int Serial_Cfg(unsigned char num, int baudrate, unsigned char parity, unsigned char data_bit, unsigned char stop_bit)
{
    int fd;
    speed_t speed;
    struct termios tios;
    char device[20];

    if (num == 1)
    {
        strcpy(device, SERIAL1);
    }

    else if (num == 2)
    {
        strcpy(device, SERIAL2);
    }

    fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
    // mylog(" fd= %d num=%d baud=%d databit=%d stop_bit=%d parity=%c\n",fd,num,baudrate,data_bit,stop_bit,parity);
    if (fd < 0)
    {
        printf("open error\n");
        return -1;
    }

#if 1
    memset(&tios, 0, sizeof(struct termios));
#else
    struct termios old_tios;
    tcgetattr(fd, &old_tios);
    memcpy(&tios, &old_tios, sizeof(struct termios));
#endif

    switch (baudrate)
    {
    case 1200:
        speed = B1200;
        break;
    case 2400:
        speed = B2400;
        break;
    case 4800:
        speed = B4800;
        break;
    case 9600:
        speed = B9600;
        break;
    case 19200:
        speed = B19200;
        break;
    case 38400:
        speed = B38400;
        break;
    case 57600:
        speed = B57600;
        break;
    case 115200:
        speed = B115200;
        break;
    case 230400:
        speed = B230400;
        break;
    case 460800:
        speed = B460800;
        break;
    case 500000:
        speed = B500000;
        break;
    case 576000:
        speed = B576000;
        break;
    case 921600:
        speed = B921600;
        break;
    case 1000000:
        speed = B1000000;
        break;
    case 1152000:
        speed = B1152000;
        break;
    default:
        speed = B9600;
        printf("error baudrate\n");
    }

    if ((cfsetispeed(&tios, speed) < 0) || (cfsetospeed(&tios, speed) < 0))
    {
        close(fd);
        return -1;
    }

    tios.c_cflag |= (CREAD | CLOCAL);
    tios.c_cflag &= ~CSIZE;

    switch (data_bit)
    {
    case 5:
        tios.c_cflag |= CS5;
        break;
    case 6:
        tios.c_cflag |= CS6;
        break;
    case 7:
        tios.c_cflag |= CS7;
        break;
    case 8:
    default:
        tios.c_cflag |= CS8;
        break;
    }

    if (stop_bit == 1)
        tios.c_cflag &= ~CSTOPB;
    else
        tios.c_cflag |= CSTOPB;

    if (parity == 'N')
    {
        tios.c_cflag &= ~PARENB;
    }
    else if (parity == 'E')
    {
        tios.c_cflag |= PARENB;
        tios.c_cflag &= ~PARODD;
    }
    else
    {
        tios.c_cflag |= PARENB;
        tios.c_cflag |= PARODD;
    }

    tios.c_cflag &= ~HUPCL;
    tios.c_iflag &= ~INPCK;
    tios.c_iflag |= IGNBRK;
    tios.c_iflag &= ~ICRNL;
    tios.c_iflag &= ~IXON;
    tios.c_lflag &= ~IEXTEN;
    tios.c_lflag &= ~ECHOK;
    tios.c_lflag &= ~ECHOCTL;
    tios.c_lflag &= ~ECHOKE;
    tios.c_oflag &= ~ONLCR;
    tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    if (parity == 'N')
    {
        /* None */
        tios.c_iflag &= ~INPCK;
    }
    else
    {
        tios.c_iflag |= INPCK;
    }
    tios.c_iflag &= ~(IXON | IXOFF | IXANY);
    tios.c_oflag &= ~OPOST;
    tios.c_cc[VMIN] = 0;
    tios.c_cc[VTIME] = 0;

    if (tcsetattr(fd, TCSANOW, &tios) < 0)
    {
        close(fd);
        return -1;
    }

    struct serial_rs485 rs485conf;
    ioctl(fd, TIOCGRS485, &rs485conf);
    rs485conf.flags |= SER_RS485_ENABLED;
    ioctl(fd, TIOCSRS485, &rs485conf);

    return fd;
}

void RTU_receive()
{
    int fd;
    fd = gSerialFd1;
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(fd, &fds);

    struct timeval tv;
    tv.tv_sec = 60;
    tv.tv_usec = 0;

    while (1)
    {
        tv.tv_sec = 3;
        tv.tv_usec = 0;
        // printf("======================================\n");
        int ret = select(fd + 1, &fds, NULL, NULL, &tv);
        if (ret == -1)
        {
            fprintf(stderr, "fail to select, error: %d, %s\n", errno, strerror(errno));
        }
        else if (ret == 0)
        {
            fprintf(stderr, "select timeout\n");
        }
        else
        {
            fprintf(stdout, "success to select\n");
            // int result =read();
        }
        if (g_Sys_Status == 4)
        {
            printf("===============\n");
            break;
        }
        else
        {
            printf("===============g_Sys_Status == 2\n");
        }
    }
}

void main() // int argc, int *argv
{

    int i;

    int ret[PRONUM];
    pthread_attr_t thread_attr;
    pthread_t thread_id;
    // struct sched_param thread_param[PRONUM];
    unsigned char myNum[PRONUM];
    int tempEnable[PRONUM];

    if (1)
    {
        gSerialFd1 = Serial_Cfg(1, 19200, 'E', 8, 1);
        pthread_attr_init(&thread_attr);
        // thread_param[0].sched_priority = RUNNETWORK_THREAD_PRIO;
        // pthread_attr_setschedpolicy(&(thread_attr[0]), SCHED_FIFO);
        // pthread_attr_setschedparam(&(thread_attr[0]), &(thread_param[0]));
        ret[0] = pthread_create(&(thread_id), &(thread_attr), (void *)RTU_receive, NULL);
        if (ret[0] != 0)
        {
            printf("pthread_create error thread_param!\n");
            // continue;
        }
        pthread_attr_destroy(&(thread_attr));
    }

    char cmdbuf[20] = {0};
    char *string;
    while (1)
    {
        printf("2input cmd:");
        memset(cmdbuf, 0, 20 * sizeof(char));
        string = fgets(cmdbuf, 20, stdin); //
        if (strcmp(cmdbuf, "2\n") == 0)
        {
            g_Sys_Status = 2;
        }
        else if (strcmp(cmdbuf, "4\n") == 0)
        {
            g_Sys_Status = 4;
        }
        else if (strcmp(cmdbuf, "6\n") == 0)
        {
            printf("RRRRRR= 6\n");
        }
        printf("%s\n", string);

        if (g_Sys_Status == 4) // 停止状态下结束所有线程
        {
            pthread_cancel(thread_id);
            pthread_join(thread_id, NULL);
            break;
        }
        usleep(5000);
    }
}