目录
一、关于线程
二、示例
三、生成效果
一、关于线程
在使用多线程前要先引用命名空间System.Threading,引用命名空间后就可以在需要的地方方便地创建并使用线程。
创建线程对象的构造方法中使用了ThreadStart()委托,当线程开始执行时,将会执行委托中定义的方法。通过IsBackground属性设置线程为后台线程,调用线程对象的Start方法启动线程,开始执行。CancellationToken方法终止线程。
创建的线程分为前台线程和后台线程,通过线程对象的IsBackground属性可以设置线程为前台线程或后台线程。前台线程与后台线程的区别是,后台线程不会使托管程序处于运行状态。也就是说,如果进程停止所有前台线程,那么系统会认为此进程处于非运行状态,将会停止所有后台线程并关闭。
适当地使用线程,可以增加程序的运行效率,使程序运行更加流畅,但是线程间的同步问题也显得尤为重要,可以使用线程锁或监视器有效地处理线程同步问题。
二、示例
// 线程技术
// 使用随机对象产生一个1~100之间的整数,单击“开始”时,动态生成100个按钮并开始计时;
// 单击事件:按钮上的数字<随机数,那么被单击的按钮变为红色,并显示字符串“小”;
// 单击事件:按钮上的数字>随机数,那么被单击的按钮变为红色,并显示字符串“大”;
// 单击事件:按钮上的数字=随机数就会弹出消息框,提示已经猜对了数字,并显示用时及猜测次数。
namespace _033
{
public partial class Form1 : Form
{
private Button? button1;
private Label? label1;
private Label? label2;
private Label? label3;
private Label? label4;
Thread? thread_1; //定义线程
readonly Random random_num = new(); //定义随机数对象
int Temp_int_num; //定义变量用于存放存机数
public Form1()
{
InitializeComponent();
Load += Form1_Load;
}
private void Form1_Load(object? sender, EventArgs e)
{
//
// button1
//
button1 = new Button
{
Location = new Point(30, 22),
Name = "button1",
Size = new Size(75, 23),
TabIndex = 0,
Text = "开始",
UseVisualStyleBackColor = true
};
button1.Click += Button1_Click;
//
// label1
//
label1 = new Label
{
AutoSize = true,
Location = new Point(206, 28),
Name = "label1",
Size = new Size(44, 17),
TabIndex = 1,
Text = "计时:"
};
//
// label2
//
label2 = new Label
{
AutoSize = true,
Location = new Point(256, 28),
Name = "label2",
Size = new Size(0, 17),
TabIndex = 2
};
//
// label3
//
label3 = new Label
{
AutoSize = true,
Location = new Point(305, 28),
Name = "label3",
Size = new Size(20, 17),
TabIndex = 3,
Text = "秒"
};
//
// label4
//
label4 = new Label
{
AutoSize = true,
Location = new Point(115, 28),
Name = "label4",
Size = new Size(43, 17),
TabIndex = 4,
Text = ""
};
//
// Form1
//
AutoScaleDimensions = new SizeF(7F, 17F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(379, 426);
Controls.Add(label4);
Controls.Add(label3);
Controls.Add(label2);
Controls.Add(label1);
Controls.Add(button1);
Name = "Form1";
StartPosition = FormStartPosition.CenterScreen;
Text = "猜数字";
FormClosed += Form1_FormClosed;
}
private void Button1_Click(object? sender, EventArgs e)
{
RemoveControl(); //清空所有无用对象
int bt_int_x = 10; //X坐标初始值为10
int bt_int_y = 60; //Y坐标初始值为60
for (int i = 0; i < 100; i++) //添加100个按钮
{
Button bt = new()
{
Text = (i + 1).ToString(), //设置button按钮的文本值
Name = (i + 1).ToString(), //设置button按钮的Name属性
Width = 35,
Height = 35,
Location = new Point(bt_int_x, bt_int_y)//设置button按钮的位置
};
bt.Click += new EventHandler(Bt_Click); //定义button按钮的事件
bt_int_x += 36; //设置下一个按钮的位置
if ((i + 1) % 10 == 0) //每10个按钮就换行
{
bt_int_x = 10; //换行后重新设置X坐标
bt_int_y += 36; //换行后重新设置Y坐标
}
Controls.Add(bt); //将button按钮放入窗体控件集合中
}
thread_1 = new Thread(delegate () //新建一条线程使用匿名方法
{
int P_int_count = 0; //初始化计数器
while (true) //开始无限循环
{
P_int_count = ++P_int_count > 100000000 ? 0 : P_int_count; //计数器累加
Invoke( //将代码交给主线程执行
(MethodInvoker)delegate //使用匿名方法
{
label2!.Text = P_int_count.ToString(); //窗体中显示计数
});
Thread.Sleep(1000); //线程睡眠1秒
}
})
{
IsBackground = true //设置线程为后台线程
};
thread_1.Start(); //开始执行线程
Temp_int_num = random_num.Next(1, 100);//生成随机数
label4!.Text = "随机数=" + Temp_int_num.ToString( );
button1!.Enabled = false; //停用开始按钮
}
/// <summary>
/// 强行关闭窗体
/// </summary>
private void Form1_FormClosed(object? sender, FormClosedEventArgs e)
{
Environment.Exit(0);
}
/// <summary>
/// 开始遍历100个按钮
/// 清空窗体中动态生成的按钮
/// </summary>
void RemoveControl()
{
for (int i = 0; i < 100; i++)
{
if (Controls.ContainsKey((i + 1).ToString())) //窗体中是否有此按钮
{
for (int j = 0; j < Controls.Count; j++) //遍历窗体控件集合
{
if (Controls[j].Name == (i + 1).ToString())//是否查找到按钮
{
Controls.RemoveAt(j); //删除指定按钮
break;
}
}
}
}
}
/// <summary>
/// 用于查找窗体中Enable属性为False控件的数量
/// 用于计算玩家有多少次没有猜中
/// </summary>
/// <returns>返回没有猜中数量</returns>
string GetCount()
{
int P_int_temp = 0; //初始化计数器
foreach (Control c in Controls) //遍历控件集合
{
if (!c.Enabled) P_int_temp++; //计数器累加
}
return P_int_temp.ToString(); //返回计数器信息
}
void Bt_Click(object? sender, EventArgs e)
{
Control? P_control = sender as Control; //将sender转换为control类型对象
if (int.Parse(P_control!.Name) > Temp_int_num)
{
P_control.BackColor = Color.Red; //设置按钮背景为红色
P_control.Enabled = false; //停用按钮
P_control.Text = "大"; //更改按钮文本
}
if (int.Parse(P_control.Name) < Temp_int_num)
{
P_control.BackColor = Color.Red; //设置按钮背景为红色
P_control.Enabled = false; //设置按钮停用
P_control.Text = "小"; //更改按钮文本
}
if (int.Parse(P_control.Name) == Temp_int_num)
{
//thread1.Abort();
CancellationToken cancellationToken = new();
CancellationToken token = cancellationToken;
Thread_Abort(token);
MessageBox.Show(string.Format("恭喜你猜对了!共猜了{0}次 用时{1}秒",
GetCount(), label2!.Text), "恭喜!"); //显示游戏信息
button1!.Enabled = true; //启用开始按钮
}
}
/// <summary>
/// 用于代替thread1!.Abort();
/// SYSLIB0006:不支持 Thread.Abort
/// 替代方案我没有深究是否有效,仅提供指明的解决方向
/// </summary>
static void Thread_Abort(CancellationToken cancellationToken)
{
// If the CancellationToken is marked as "needs to cancel",
// this will throw the appropriate exception.
cancellationToken.ThrowIfCancellationRequested();
}
}
}
三、生成效果