欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux多线程应用程序--新手练习程序

程序员文章站 2022-06-19 10:59:31
...

涉及的内容:任务队列、自旋锁、信号处理、生产者-消费者

可以用这个程序练习一下gdb多线程调试,编译命令:make v=debug

// task_queue.c

#include "task_queue.h"

Q_NODE *q_head = NULL, *q_tail = NULL, *q_current = NULL;
pthread_spinlock_t queue_spinlock;
int g_param = 0;

static pthread_t pid_producer, pid_consumer;

int init_queue(){
	q_head = (Q_NODE *)malloc(sizeof(Q_NODE));
	if (q_head == NULL) {
		printf("%s: %d: %s\n", __func__, __LINE__, "q_head init failed!");
		return -1;
	}
	q_head->func = NULL;
	q_head->next = NULL;

	q_tail = q_head;
	q_current = q_head->next;

	return 0;
}

void destory_queue(){
	printf("\nCtrl+C pressed!\n");
	printf("pid_producer pthread_cancel result: %d\n", pthread_cancel(pid_producer));
	printf("pid_consumer pthread_cancel result: %d\n", pthread_cancel(pid_consumer));
	printf("pid_producer pthread_join result: %d\n", pthread_join(pid_producer, NULL));
	printf("pid_consumer pthread_join result: %d\n", pthread_join(pid_consumer, NULL));

	while (q_current != NULL){
		q_current = q_current->next;
		free(q_head->next);
		q_head->next = q_current;
	}
	free(q_head);
	exit(0);
}

void show_queue(){
	static Q_NODE *q_iterator;
	pthread_spin_lock(&queue_spinlock);
	q_iterator = q_head->next;
	for(int i = 1; q_iterator != NULL; i++){
		printf("Node %d, param %d\n", i, *(int *)(q_iterator->param));
		q_iterator = q_iterator->next;
	}
	pthread_spin_unlock(&queue_spinlock);
}

int main(){
	if (init_queue()){
		return -1;
	}
	pthread_spin_init(&queue_spinlock, PTHREAD_PROCESS_PRIVATE);

	if (pthread_create(&pid_producer, NULL, producer, NULL)) {
		printf("%s: %d: %s\n", __func__, __LINE__, "producer process init failed!");
		return -2;
	}
	if (pthread_create(&pid_consumer, NULL, consumer, NULL)) {
		printf("%s: %d: %s\n", __func__, __LINE__, "consumer process init failed!");
		return -3;
	}

	signal(SIGINT, destory_queue); 

	for(;;){
		show_queue();
		sleep(1);
	}

	return 0;
}

// producer.c

#include "task_queue.h"

int task_show_param(void *param){
	printf("%s: %d: %s %d\n", __func__, __LINE__, "In task_show_param: param = ", *(int *)param);
	return *(int *)param;
}

int task_minus_param(void *param){
	*(int *)param -= 5;
	printf("%s: %d: %s %d\n", __func__, __LINE__, "In task_minus_param: param = ", *(int *)param);
	return *(int *)param;
}

void *producer(void *param){
	(void)param;
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
	
	for(; ; g_param++) {
		pthread_spin_lock(&queue_spinlock);
		q_tail->next = (Q_NODE *)malloc(sizeof(Q_NODE));
		if (q_tail->next == NULL) {
			printf("%s: %d: %s\n", __func__, __LINE__, "task produced failed!");
			exit(-1);
		}
		q_tail = q_tail->next;
		q_tail->next = NULL;

// assign task
		if (g_param < 5) {
			q_tail->func = task_show_param;
		} else {
			q_tail->func = task_minus_param;
		}
		
		q_tail->param = (void *)&g_param;

		pthread_spin_unlock(&queue_spinlock);
		
		printf("%s: %d: %s %d\n", __func__, __LINE__, "In producer: g_param = ", g_param);
		pthread_testcancel();
		sleep(1);
	}
	return NULL;
}


// consumer.c

#include "task_queue.h"

void *consumer(void *param){
	(void)param;
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);

	for(;;)
	{
		pthread_spin_lock(&queue_spinlock);
		if (q_current != NULL){
			q_current->func(q_current->param);
			printf("%s: %d: %s %d\n", __func__, __LINE__, "In consumer: g_param = ", *(int *)q_current->param);

			if (q_current != q_tail){
				q_current = q_current->next;
				free(q_head->next);
				q_head->next = q_current;
			} else{
				free(q_head->next);
				q_head->next = NULL;
				q_current = q_head->next;
				q_tail = q_head;
			}
			pthread_spin_unlock(&queue_spinlock);
			
			sleep(1);
		} else {
			q_current = q_head->next;
			pthread_spin_unlock(&queue_spinlock);
			
			printf("%s: %d: %s\n", __func__, __LINE__, "In consumer: waiting for producer!");
			sleep(1);
		}
		pthread_testcancel();
	}

	exit(0);
}
// task_queue.h

#ifndef TASK_QUEUQ_H
#define TASK_QUEUQ_H

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

typedef struct _NODE{
	int (*func)(void *);
	void *param;
	struct _NODE *next;
}Q_NODE;

void *consumer(void *param);
void *producer(void *param);

extern Q_NODE *q_head, *q_tail, *q_current;
extern pthread_spinlock_t queue_spinlock;
extern int g_param;

#endif
# Makefile

objects = task_queue.o producer.o consumer.o
cflags = -lpthread
cc = gcc

ifeq ($(v), debug)
	cflags += -Wall -g3 -O0 -fsanitize=address
endif

all: $(objects)
	$(cc) *.c -o task_queue $(cflags)

consumer.o: task_queue.h
producer.o: task_queue.h
task_queue.o: task_queue.h

.PHONY: clean
clean:
	rm -rf *.o task_queue

执行结果:

Linux多线程应用程序--新手练习程序