我遇到一个奇怪的问题。在我的开发系统上,一切运行良好,但是在生产系统上运行代码会增加额外的参数。这是代码。
public string Read(Setting SettingID, string SettingValue, int GameID)
{
SqlCommand sqlText;
string SettingName = SettingsNames[(int)SettingID];
using (SqlConnection cn = new SqlConnection(DataHandlers.ConnString))
{
sqlText = cn.CreateCommand();
sqlText.CommandType = CommandType.StoredProcedure;
sqlText.CommandText = "Proc_Settings";
sqlText.Parameters.Clear();
sqlText.Parameters.Add(new SqlParameter("SettingName", SettingName));
sqlText.Parameters.Add(new SqlParameter("SettingValue", SettingValue));
sqlText.Parameters.Add(new SqlParameter("Dir", Direction.Read));
sqlText.Parameters.Add(new SqlParameter("GameID", GameID));
sqlText.Parameters.Add("@Return", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
前两个参数可以添加。在第三个参数上添加'DIR'和@Return,但是@Return是输入。第4个参数也会发生同样的情况,然后将第5个参数添加为返回值。发生问题时,正在从另一个线程调用该函数。该线程是一个COM端口处理程序。如果我禁用BIOS中的com端口,则可以正常工作,这是有道理的,因为我的开发计算机没有相同数量的端口,因此缺少该设备的端口。一旦启用端口并启动例程,轮询线程即开始出现问题。我研究了VS中的不同线程,唯一需要我编写与该问题相关的代码的线程是我正在调试的当前线程。我在这里引起线程冲突吗?
这是轮询例程
private void Poll()
{
Actions.init(buffer, length, ComDll, Port); //Function to Initialize
while (Active)
{
// Process the com port
// Currently doesn't get here
}
}
这是初始化函数,
public static void init(byte[] buffer, int length, ID003CommandCreater ComDll, SerialPort Port)
{
byte enable1 = 0;
byte enable2 = 0;
byte[] status = new byte[255]; //Buffer to read data from the serial port
bool initializing = true;
while (initializing)
{
try
{
// Initializes the device
ComDll.Reset(buffer);
length = (int)buffer[1];
Port.Write(buffer, 0, length);
System.Threading.Thread.Sleep(3000);
Port.Read(status, 0, 255); //Fails when device not connected
… More init commands sent
initializing = false;
}
catch
{
if (Port.PortName != settings.Read(Settings.Setting.ComPort, Port.PortName, 0))
{
Port.Close();
initializing = false;
}
//JCM.BVstatus = "Com Failure";
//JCM.bvComFailure = true;
}
}
}
这是错误。
“ System.Data.SqlClient.SqlException(0x80131904):过程或函数Proc_Settings指定了太多参数。\ n过程或函数Proc_Settings指定了太多参数。\ r \ n位于System.Data.SqlClient.SqlConnection.OnError (System.Data.SqlClient.SqlException异常,System.Boolean breakConnection,System.Action 1[T] wrapCloseInAction) [0x0004c] in <290425a50ff84a639f8c060e2d4530f6>:0 \r\n at (wrapper remoting-invoke-with-check) System.Data.SqlClient.SqlConnection.OnError(System.Data.SqlClient.SqlException,bool,System.Action
1 1[T] wrapCloseInAction) [0x00013] in <290425a50ff84a639f8c060e2d4530f6>:0 \r\n at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning (System.Data.SqlClient.TdsParserStateObject stateObj, System.Boolean callerHasConnectionLock, System.Boolean asyncClose) [0x00152] in <290425a50ff84a639f8c060e2d4530f6>:0 \r\n at System.Data.SqlClient.TdsParser.TryRun (System.Data.SqlClient.RunBehavior runBehavior, System.Data.SqlClient.SqlCommand cmdHandler, System.Data.SqlClient.SqlDataReader dataStream, System.Data.SqlClient.BulkCopySimpleResultSet bulkCopyHandler, System.Data.SqlClient.TdsParserStateObject stateObj, System.Boolean& dataReady) [0x009b9] in <290425a50ff84a639f8c060e2d4530f6>:0 \r\n at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData () [0x00040] in <290425a50ff84a639f8c060e2d4530f6>:0 \r\n at System.Data.SqlClient.SqlDataReader.get_MetaData () [0x00031] in <290425a50ff84a639f8c060e2d4530f6>:0 \r\n at (wrapper remoting-invoke-with-check) System.Data.SqlClient.SqlDataReader.get_MetaData()\r\n at System.Data.SqlClient.SqlCommand.FinishExecuteReader (System.Data.SqlClient.SqlDataReader ds, System.Data.SqlClient.RunBehavior runBehavior, System.String resetOptionsString) [0x000d3] in <290425a50ff84a639f8c060e2d4530f6>:0 \r\n at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds (System.Data.CommandBehavior cmdBehavior, System.Data.SqlClient.RunBehavior runBehavior, System.Boolean returnStream, System.Boolean async, System.Int32 timeout, System.Threading.Tasks.Task& task, System.Boolean asyncWrite, System.Data.SqlClient.SqlDataReader ds) [0x004d8] in <290425a50ff84a639f8c060e2d4530f6>:0 \r\n at System.Data.SqlClient.SqlCommand.RunExecuteReader (System.Data.CommandBehavior cmdBehavior, System.Data.SqlClient.RunBehavior runBehavior, System.Boolean returnStream, System.Threading.Tasks.TaskCompletionSource
1 [TResult]完成,System.Int32超时,System.Threading.Tasks.Task&任务,System.Boolean asyncWrite,System.String方法)[0x00079]在<290425a50ff84a639f8c060e2d4530f6>:0 \ r \ n中位于System.Data.SqlClient.SqlCommand.RunExecuteReader(System.Data.CommandBehavior cmdBehavior,System.Data.SqlClient.RunBehavior runBehavior,System.Boolean returnStream,System.String方法)[0x0000b]在System.Data.SqlClient.SqlCommand.ExecuteReade的<290425a50ff84a639f8c060e2d4530f6>:0 \ r \ n中在<290425a50ff84a639f8c060e2d4530f6>:0 \ r \ n中的r(System.Data.CommandBehavior行为)[0x0003c]:0 \ r \ n在<290425a50ff84a639f8c060e2d4530f6>:0 \ r \ n at E. \中的Settings.Read(设置+设置SettingID,System.String SettingValue,System.Int32 GameID)[0x000cb]处的System.Data.SqlClient.SqlCommand.ExecuteReader()\ r \ n Unity \ xxxx \ Assets \ xxxx \ Scripts \ Database \ Settings.cs:192 \ r \ nClientConnectionId:42a5adfe-d934-496e-b678-456fde7d2622 \ r \ n错误编号:8144,状态:2,类:16“
我之前使用过一些线程,但是可能会误解其中的一部分。在这种情况下,初始化必须在轮询线程继续之前成功完成。初始化完成后,线程将进入循环以处理com端口。如果我不等待硬件,则循环将尝试从com端口发送更多数据,这将使配置混乱。要成功初始化硬件,我必须按顺序执行大约6个步骤。第一条命令将重置设备,并且仅用3秒钟即可初始化设备,然后我才能继续与之交谈。我是否希望线程继续?该线程仅运行设备的代码,没有其他运行。所有其他代码继续。从多个线程调用Read例程。在整个程序中都使用它。
答案 0 :(得分:0)
使用System.Threading.Thread.Sleep(3000);
时,您将阻塞当前线程作为等待任务完成的一种方式,这可能导致死锁和阻塞上下文线程
当您等待一定时间时,您宁愿等待await System.Threading.Tasks.Task.Delay(3000);
。因为此命令不会阻止当前线程。
要使用此命令,您需要使方法异步。
您的代码是异步的:
public static async System.Threading.Tasks.Task InitAsync(
byte[] buffer,
int length,
ID003CommandCreater ComDll,
SerialPort Port)
{
byte enable1 = 0;
byte enable2 = 0;
byte[] status = new byte[255]; //Buffer to read data from the serial port
bool initializing = true;
while (initializing) {
try {
// Initializes the device
ComDll.Reset(buffer);
length = (int)buffer[1];
Port.Write(buffer, 0, length);
// Doesn't block thread anymore, because we wait until the task is finished.
await System.Threading.Tasks.Task.Delay(300);
Port.Read(status, 0, 255);
… More init commands sent
initializing = false;
}
catch {
if (Port.PortName != settings.Read(Settings.Setting.ComPort, Port.PortName, 0)) {
Port.Close();
initializing = false;
}
//JCM.BVstatus = "Com Failure";
//JCM.bvComFailure = true;
}
}
}
我建议您也使调用此方法的方法也异步,但是如果不可能的话,则需要确保没有死锁,并且可以通过较小的解决方法来实现。
要在同步方法中调用异步方法,我们首先需要添加一个清除线程的类,以免阻塞线程
NoSynchronizationContextScope类:
public static class NoSynchronizationContextScope {
public static Disposable Enter() {
var context = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
return new Disposable(context);
}
public struct Disposable : IDisposable {
private readonly SynchronizationContext _synchronizationContext;
public Disposable(SynchronizationContext synchronizationContext) {
_synchronizationContext = synchronizationContext;
}
public void Dispose() =>
SynchronizationContext.SetSynchronizationContext(_synchronizationContext);
}
}
现在,如果我们使用这些代码行,则可以在代码中的任何地方调用异步方法。
在同步方法中调用异步方法:
private void MySynchronousMethodLikeDisposeForExample() {
using (NoSynchronizationContextScope.Enter()) {
InitAsync().Wait();
}
}