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

Zynq-Linux移植学习笔记之43-linux下多线程应用示例

程序员文章站 2024-03-22 12:12:58
...

1、背景介绍

虽然ZYNQ上面的ARM没有intel X86性能那么强悍,但完全可以在ARM上面跑多线程任务,前提是ZYNQ上要运行linux操作系统,这里给一个多线程的应用编写示例。

 

2、应用框架

这里在main函数里面调用thread_create()函数创建了三个线程,注意创建线程后main函数不能直接退出,需要有个死循环,否则线程根本无法运行。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <linux/kernel.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <semaphore.h>
#include "srio.h"

unsigned char send_buf[16384] ={0};
unsigned char recv_buf[16384] ={0};

#define RX_BASE  0x2000000

unsigned int *tx_Recv;//收数地址
unsigned int pRcvDataBuf[16384];

void *data_recv(void *arg)
{
	int ret=0;
	udp_create_socket_recv();
}

void *data_send(void *arg)
{
	int ret=0;
	int i=0;
	udp_create_socket_send();
	for(i=0;i<1500;i++)
	{
		send_buf[i]=i;
	}
	while(1)
	{
		ret=udp_send_data(1500);
		sleep(10);
	}

}

void *srio_data_recv(void *arg)
{
	int fdRecv;
	int count=0;
	unsigned int val=0;
	unsigned int i=0;
	int ret=0;

	fdRecv = open("/dev/mem", O_RDWR | O_SYNC);
	if (fdRecv < 0)
	{
		printf("cannot open /dev/mem.");
		return 0;
	}

	//map physical memory 0-80M bytes
	tx_Recv = (int *) mmap(NULL, 0x800, PROT_READ | PROT_WRITE, MAP_SHARED, fdRecv, RX_BASE);
	if (tx_Recv < 0)
	{
		printf("mmap failed.");
		return 0;
	}

	while(1)
	{
		sleep(2);
		count=GetGpioReg(srio_cfg_0,120);//70
		printf("count is %d \r\n",count);
		if(count>0)//获取到收数中断,进行如下处理
		{
			printf("get data!\n");
			SetGpioReg (srio_cfg_0, DBELL_RD_REG, 0x80000000);
			SetGpioReg (srio_cfg_0, DBELL_RD_REG, 0x00000000);
			val=GetGpioReg(srio_cfg_0,124);

			printf("doorbell count is %d doorbell info is 0x%x\r\n",count,val);

			if(val==0xdcba)
			{
				for(i=0;i<320;i++)
				{
					*(pRcvDataBuf+i) = *(tx_Recv+i);//bytes 收到的数据第一个为空闲码,先强行避免
				}
				for(i=0;i<10;i++)
				{
					printf("i = %d, data is 0x%x\n",i,*(pRcvDataBuf+i));
				}
				memcpy((void*)send_buf,(void*)pRcvDataBuf,1280);
			//	ret=udp_send_data(1280);
			}

		}

	}
	munmap(tx_Recv, 0x800); //destroy map memory
	close(fdRecv);
	return 0;
}

void thread_create()
{
	pthread_t thr1,thr2,thr3;
	if( pthread_create(&thr1,NULL,data_recv,0)!=0)
	{
		printf("create thread1 failed.\n");
		return;
	}
	if( pthread_create(&thr2,NULL,data_send,0)!=0)
	{
		printf("create thread2 failed.\n");
		return;
	}
	if( pthread_create(&thr3,NULL,srio_data_recv,0)!=0)
	{
		printf("create thread3 failed.\n");
		return;
	}
}

int main()
{
	unsigned int _data;
    printf("Linux App Recv UDP mode 2019-8-22\n");
    NetInit(0,4);

    srio_init();

	printf("read srio link status\n");
	_data=GetGpioReg(XPAR_SRIO_AXI_CONFIG_0_S00_AXI_BASEADDR,SRIO_LNK_REG_1);
	printf("SRIO_LNK_REG_1 = 0x%x\n",_data);

	thread_create();

	while(1)
	{
		sleep(3);
	}
    return 0;
}

然后在SDK中编应用时需要添加pthread库,如下图:

Zynq-Linux移植学习笔记之43-linux下多线程应用示例

3、线程优先级设定

上面示例中采用的线程默认优先级,通过查阅资料能发现,这种默认优先级是

SCHED_OTHER(是Linux默认的分时调度策略):它是默认的线程分时调度策略,所有的线程的优先级别都是0(不使用sched_param结构体的sched_priority成员),如果系统使用这种调度策略,程序将无法设置线程的优先级。这种调度策略也是抢占式的,当高优先级的线程准备运行的时候,当前线程将被抢占并进入等待队列。这种调度策略仅仅决定线程在可运行线程队列中的具有相同优先级的线程的运行次序。(使用此方式的代码不可移植)

更多内容参考这篇博客:https://www.cnblogs.com/tianzeng/p/9192706.html

 

如果需要用户手动设定线程优先级,可以参考如下代码:

void startFunc()
{
	pthread_t pid1;

	pthread_attr_t attr1;
	struct sched_param param1;

	pthread_attr_init(&attr1);

	pthread_attr_setschedpolicy(&attr1, SCHED_RR);
	param1.sched_priority = 54;
	pthread_attr_setschedparam(&attr1, &param1);


	if(pthread_create(&pid1,&attr1,bitfunc,0)!=0)
	{
		printf("<E>create bitfunc failed.\n");
	}else
	{
		printf("<E>create bitfunc successful.\n");
	}
}

 

以上就是创建了一个优先级为54的线程。数字越大,线程优先级越高。